Thread overview
how to get rid of "cannot deduce function from argument types" elegantly
Jun 13, 2016
Christian Köstlin
Jun 13, 2016
Ali Çehreli
Jun 14, 2016
pineapple
June 14, 2016
I made a small (could be reduced further) example that creates and walks a templated binary tree. The tree also gets a factory function to use type deduction to conveniently construct a tree. Unfortunately this does not compile, if I remove the three ugly methods between /* these should go */ comments.

```
fibertest.d(49): Error: template fibertest.tree cannot deduce function
from argument types !()(int, typeof(null), typeof(null)), candidates are:
fibertest.d(41):        fibertest.tree(T)(T node, Tree!T left, Tree!T right)
```

Is there a more elegant way to fix this?

Another fix would be to provide 4 factory functions like this (still not
really nice):
```
tree(Tree!T left, T node, Tree!T right) {...}
tree(T node, Tree!T right) {...}
tree(Tree!T left, T node) {...}
tree(T node) {...}
```

```d
import std.concurrency, std.stdio, std.range;

class Tree(T) {
  Tree!T left;
  T node;
  Tree!T right;

  this(Tree!T left, T node, Tree!T right) {
    this.left = left;
    this.node = node;
    this.right = right;
  }

  auto inorder() {
    return new Generator!T(() => yieldAll(this));
  }

  private void yieldAll(Tree!T t) {
    if (t is null) return;

    yieldAll(t.left);
    yield(t.node);
    yieldAll(t.right);
  }
}

/* these should go */

Tree!T tree(T)(typeof(null) left, T node, typeof(null) right) {
  return new Tree!T(null, node, null);
}
Tree!T tree(T)(Tree!T left, T node, typeof(null) right) {
  return new Tree!T(left, node, null);
}
Tree!T tree(T)(typeof(null) left, T node, Tree!T right) {
  return new Tree!T(null, node, right);
}

/* these should go */

Tree!T tree(T)(Tree!T left, T node, Tree!T right) {
  return new Tree!T(left, node, right);
}

void main(string[] args) {
  //     /3
  //   /2
  //  1
  auto t1 = tree(tree(tree(null, 1, null), 2, null), 3, null);
  // 1
  //  \2
  //    \3
  auto t2 = tree(null, 1, tree(null, 2, tree(null, 3, null)));
  writeln(t1.inorder());
  writeln(t2.inorder());
  writeln(t1.inorder().array == t2.inorder().array);
}
```
June 13, 2016
On 06/13/2016 03:30 PM, Christian Köstlin wrote:

> Tree!T tree(T)(Tree!T left, T node, Tree!T right) {
>   return new Tree!T(left, node, right);
> }

This works but I don't know whether it's a bug or not:

Tree!T tree(TT, T)(TT left, T node, TT right) {
  return new Tree!T(left, node, right);
}

Perhaps this is better:

Tree!T tree(TL, T, TR)(TL left, T node, TR right) {
  return new Tree!T(left, node, right);
}

Ali

June 14, 2016
On Monday, 13 June 2016 at 22:54:13 UTC, Ali Çehreli wrote:
> Tree!T tree(TL, T, TR)(TL left, T node, TR right) {
>   return new Tree!T(left, node, right);
> }
>

There's also this:

    Tree!T tree(TL, T, TR)(TL left, T node, TR right) if(
        (is(TL == Tree!T) || is(TL == typeof(null))) &&
        (is(TR == Tree!T) || is(TR == typeof(null)))
    ){
      return new Tree!T(left, node, right);
    }
June 14, 2016
On 6/14/16 6:05 AM, pineapple wrote:
> On Monday, 13 June 2016 at 22:54:13 UTC, Ali Çehreli wrote:
>> Tree!T tree(TL, T, TR)(TL left, T node, TR right) {
>>   return new Tree!T(left, node, right);
>> }
>>
>
> There's also this:
>
>     Tree!T tree(TL, T, TR)(TL left, T node, TR right) if(
>         (is(TL == Tree!T) || is(TL == typeof(null))) &&
>         (is(TR == Tree!T) || is(TR == typeof(null)))

Alternative: if(is(typeof({Tree!T x = TL.init; x = TR.init; })))

This may seem similar, but actually can accept things that convert to Tree!T as well.

The issue with the OP code is that the compiler is trying to match T with the two null parameters, and can't work out the deduction.

-Steve