In looking at std::apply references from cpprefrence I noticed that function templates cannot be passed as callable object of std::apply. Let's consider the following function template:
template<typename T>
T add_generic(T first, T second) { return first second; }
we can't call:
std::cout << std::apply(add_generic, std::make_pair(2.0f, 3.0f)) << '\n'; // Error: can't deduce the function type
Note that this is not the same question as this question. In that answer, the author writes a lambda expression without explicit template parameters.
std::cout << std::apply(
[](auto first, auto second) { return add_generic(first, second); },
std::make_tuple(2.0f,3.0f)) << '\n';
but as you know in c 20 you can have lambda expressions with explicit template parameter list. So I tried this feature to this case and surprisingly the compiler did not raise any errors.
std::apply([]<typename T>(T first,T second){
return first second;
},std::make_pair(2.0,3.0));
Why will the compiler be able to deduce type in the last case? Is there any difference between the two?
CodePudding user response:
A function template is not a function, just like a cookie cutter is not a cookie. C templates create new functions for every set of template arguments. And this is precisely why add_generic
is not a viable argument. It's not a function, it cannot be passed around as a value. To obtain the function, the compiler needs to deduce the template arguments. But it can only do that inside apply
after the callable has been passed. Chicken and egg right there.
Why does a lambda work? Because it's not a plain function either. It produces a hidden object type
struct __lambda_at_line_N {
template<typename T>
auto operator()(T first, T second) { /* ... */ }
};
And passes that
std::apply(__lambda_at_line_N{},std::make_pair(2.0,3.0));
This is an actual object, a value. Its type does not depend on the template argument deduction that needs to happen inside std::apply
to call operator()
. That's why it works.