3

Say I have this function:

template <typename T>
void foo(function<T(const T&, const T&)> op, const T& lhs, const T& rhs) {
    cout << op(lhs, rhs) << endl;
}

This is legal code:

function<int(const int&, const int&)> op = plus<int>();

foo(op, 13, 42);

But when I do this:

foo(plus<int>(), 13, 42)

I get the error:

No matching function for call to foo(std::plus<int>, int, int)

Why can I initialize an object of type function<int(const int&, const int&)> from plus<int>() but I cannot pass plus<int>() into an parameter of type function<T(const T&, const T&)>? Is it something having to do with the template?

Jonathan Mee
  • 37,899
  • 23
  • 129
  • 288
  • 3
    Implicit type conversions do not work during template argument deduction. – Arunmu Nov 30 '16 at 19:41
  • 1
    @Arunmu I think there are exceptions from that rule: [example](http://melpon.org/wandbox/permlink/ld8NyDotgjK7B7WT) – W.F. Nov 30 '16 at 19:45
  • @Arunmu That is the answer cause it works if I remove the template: http://ideone.com/bfjy3p So how do I know the conversion between `plus()` and `function` is implicit? – Jonathan Mee Nov 30 '16 at 19:46
  • 1
    @W.F Yes, I think there are exceptions for array to pointer and function to function pointer decay. – Arunmu Nov 30 '16 at 19:47
  • @JonathanMee There is no template deduction happening in your example ( in the comment ). And the constructor of `std::function` is not `explicit`. So it can happiliy construct an function object from the functor (`std::plus`) – Arunmu Nov 30 '16 at 19:49
  • Replacing the template with a generic lambda would work: `auto foo = [](auto op, const auto& lhs, const auto& rhs) { std::cout << op(lhs, rhs) << '\n'; };` – wally Nov 30 '16 at 19:52
  • Is there a way for me to force the construction other than call it explicitly, like: `foo(function(plus()), 13, 42)` – Jonathan Mee Nov 30 '16 at 19:53
  • 1
    You could just use `foo(std::plus{}, 13, 42);` – wally Nov 30 '16 at 19:54
  • @flatmouse Your lambda works simply because it is using `auto`. I can do that in the function too, but I want to force the types to be linked: http://ideone.com/IPMRYe – Jonathan Mee Nov 30 '16 at 19:57
  • @flatmouse Your second comment works because you specify the type of `T` before supplying arguments. That is probably the best plan to be fair. – Jonathan Mee Nov 30 '16 at 19:59
  • If you can use generic functions then that should be best. What do you mean by "force types to be linked"? – wally Nov 30 '16 at 20:07
  • @flatmouse For example if we use the `auto` types I can do this: `foo(plus(), 13, 42)` Which I want to prevent. – Jonathan Mee Nov 30 '16 at 20:11

1 Answers1

2

Quoting from the Standard section 14.8.1.6:

Implicit conversions (Clause 4) will be performed on a function argument to convert it to the type of the corresponding function parameter if the parameter type contains no template-parameters that participate in template argument deduction.

This does not work in your case because the template parameters have not been provided explicitly. The compiler needs to do a deduction. Thus as per the above, it will not do the implicit conversion from functor to std::function.

So, you can do (As mentioned by @flatmouse in the comment):

foo<int>(plus<int>(), 13, 42);

This works because there is no template argument deduction that needs to be performed since all the template parameters are explicitly specified. And as per the above quote from standard, the implicit conversion should work for this.

Arunmu
  • 6,837
  • 1
  • 24
  • 46