www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Frequent cannot deduce function from argument types

reply Edwin van Leeuwen <edder tkwsping.nl> writes:
Just wondering if anyone has any tips on how to solve/avoid 
"cannot deduce function from argument types" when relying on 
template programming.

I run into these problems all the time. Current one was when I 
tried:

```
auto ys = NumericLabel(groupedAes.front.map!((t)=>t.y));
```

NumericLabel is a pretty minimal templated InputRange, with as 
only requirement on the argument that it is also an InputRange. I 
then get the following compile error:

```
source/ggplotd/geom.d(83,35): Error: struct 
ggplotd.aes.NumericLabel cannot ded
uce function from argument types !()(MapResult!(__lambda2, 
FilterResult!(__lamb
da2, Aes!(double[], "x", double[], "y", string[], "colour")))), 
candidates are:
source/ggplotd/aes.d(515,1):        ggplotd.aes.NumericLabel(T) 
if (isInputRang
e!T)
```

As far as I know MapResult always returns an input range and as 
you can see there is only one candidate of NumericLabel, so to be 
honest it looks relatively straightforward to me.

Now I can define the type specifically (and/or typeof) but it 
seems like there should be a better way.

In this case typeof isn't even happy:
```
source/ggplotd/geom.d(84,17): Error: constructor 
ggplotd.aes.NumericLabel!(MapResult!(__lambda2, 
FilterResult!(__lambda2, Aes!(string[], "x", string[], "y", 
string[], "colour")))).NumericLabel.this (MapResult!(__lambda2, 
FilterResult!(__lambda2, Aes!(string[], "x", string[], "y", 
string[], "colour"))) range) is not callable using argument types 
(MapResult!(__lambda3, FilterResult!(__lambda2, Aes!(string[], 
"x", string[], "y", string[], "colour"))))
```

If we look closely, it expects a __lambda2 as the MapResult 
argument, but it gets a __lambda3.


I am able to work around it by converting the mapresult to an 
array, but I'd rather use a lazy solution.
Oct 16 2015
next sibling parent John Colvin <john.loughran.colvin gmail.com> writes:
On Friday, 16 October 2015 at 15:48:59 UTC, Edwin van Leeuwen 
wrote:
 Just wondering if anyone has any tips on how to solve/avoid 
 "cannot deduce function from argument types" when relying on 
 template programming.

 I run into these problems all the time. Current one was when I 
 tried:

 ```
 auto ys = NumericLabel(groupedAes.front.map!((t)=>t.y));
 ```

 NumericLabel is a pretty minimal templated InputRange, with as 
 only requirement on the argument that it is also an InputRange. 
 I then get the following compile error:

 ```
 source/ggplotd/geom.d(83,35): Error: struct 
 ggplotd.aes.NumericLabel cannot ded
 uce function from argument types !()(MapResult!(__lambda2, 
 FilterResult!(__lamb
 da2, Aes!(double[], "x", double[], "y", string[], "colour")))), 
 candidates are:
 source/ggplotd/aes.d(515,1):        ggplotd.aes.NumericLabel(T) 
 if (isInputRang
 e!T)
 ```

 As far as I know MapResult always returns an input range and as 
 you can see there is only one candidate of NumericLabel, so to 
 be honest it looks relatively straightforward to me.

 Now I can define the type specifically (and/or typeof) but it 
 seems like there should be a better way.

 In this case typeof isn't even happy:
 ```
 source/ggplotd/geom.d(84,17): Error: constructor 
 ggplotd.aes.NumericLabel!(MapResult!(__lambda2, 
 FilterResult!(__lambda2, Aes!(string[], "x", string[], "y", 
 string[], "colour")))).NumericLabel.this (MapResult!(__lambda2, 
 FilterResult!(__lambda2, Aes!(string[], "x", string[], "y", 
 string[], "colour"))) range) is not callable using argument 
 types (MapResult!(__lambda3, FilterResult!(__lambda2, 
 Aes!(string[], "x", string[], "y", string[], "colour"))))
 ```

 If we look closely, it expects a __lambda2 as the MapResult 
 argument, but it gets a __lambda3.


 I am able to work around it by converting the mapresult to an 
 array, but I'd rather use a lazy solution.
My first steps would be to try pragma(msg, isInputRange!(typeof(groupedAes.front.map!((t)=>t.y)))); followed by pragma(msg, isInputRange!(typeof(groupedAes.front))); then pragma(msg, typeof(groupedAes.front)); to see at what level it's going wrong.
Oct 16 2015
prev sibling parent John Colvin <john.loughran.colvin gmail.com> writes:
On Friday, 16 October 2015 at 15:48:59 UTC, Edwin van Leeuwen 
wrote:
 Just wondering if anyone has any tips on how to solve/avoid 
 "cannot deduce function from argument types" when relying on 
 template programming.

 I run into these problems all the time. Current one was when I 
 tried:

 ```
 auto ys = NumericLabel(groupedAes.front.map!((t)=>t.y));
 ```

 NumericLabel is a pretty minimal templated InputRange, with as 
 only requirement on the argument that it is also an InputRange. 
 I then get the following compile error:

 ```
 source/ggplotd/geom.d(83,35): Error: struct 
 ggplotd.aes.NumericLabel cannot ded
 uce function from argument types !()(MapResult!(__lambda2, 
 FilterResult!(__lamb
 da2, Aes!(double[], "x", double[], "y", string[], "colour")))), 
 candidates are:
 source/ggplotd/aes.d(515,1):        ggplotd.aes.NumericLabel(T) 
 if (isInputRang
 e!T)
 ```

 As far as I know MapResult always returns an input range and as 
 you can see there is only one candidate of NumericLabel, so to 
 be honest it looks relatively straightforward to me.
Without seeing more code I can't be 100% sure, but I think it's just that you're expecting explicit function template instantiation (IFTI) for work for constructors, but it doesn't. you have to explicitly provide the template arguments or use a free function that forwards to the constructor.
 Now I can define the type specifically (and/or typeof) but it 
 seems like there should be a better way.

 In this case typeof isn't even happy:
 ```
 source/ggplotd/geom.d(84,17): Error: constructor 
 ggplotd.aes.NumericLabel!(MapResult!(__lambda2, 
 FilterResult!(__lambda2, Aes!(string[], "x", string[], "y", 
 string[], "colour")))).NumericLabel.this (MapResult!(__lambda2, 
 FilterResult!(__lambda2, Aes!(string[], "x", string[], "y", 
 string[], "colour"))) range) is not callable using argument 
 types (MapResult!(__lambda3, FilterResult!(__lambda2, 
 Aes!(string[], "x", string[], "y", string[], "colour"))))
 ```

 If we look closely, it expects a __lambda2 as the MapResult 
 argument, but it gets a __lambda3.


 I am able to work around it by converting the mapresult to an 
 array, but I'd rather use a lazy solution.
Sadly lambdas aren't currently comparable for equality. Maybe on day... If you use the string lambda "a.y" it will probably work. The more general workaround is to create a temporary variable and then use typeof on that, then use that temporary variable. The idiomatic solution in this case though is to use a function as mentioned above.
Oct 16 2015