Reputation: 199
here is the sample code
#include <iostream>
template<typename T>
T foo(T(*fp)())
{
return fp();
}
int main()
{
std::cout<<foo([]->int{ return 1; });
}
when I compiled the code above, compiler says it cannot deduce the template argument, but I have specified the return type of lambda.
Upvotes: 5
Views: 509
Reputation: 172924
foo
takes function pointer while you're passing a lambda, but implicit conversion (from lambda to function pointer) won't be considered in template argument deduction for T
, which makes the invocation failing.
Type deduction does not consider implicit conversions (other than type adjustments listed above): that's the job for overload resolution, which happens later.
You can specify template argument explicitly:
foo<int>([]()->int{ return 1; });
// ^^^^^
Or convert lambda to function pointer by operator+
or static_cast
.
foo(+[]()->int{ return 1; });
// ^
foo(static_cast<int(*)()>([]()->int{ return 1; }));
// ^^^^^^^^^^^^^^^^^^^^^^ ^
BTW: Omitted parameter list used with trailing return type is a C++23 lambda feature. (So I added ()
s.) And as @max66 suggested without trailing return type the lambda works fine too; the return type would be deduced automatically, such as foo(+[]{ return 1; });
.
Upvotes: 7
Reputation: 67733
If you don't want to change the call site, you can always just change foo
so it can take a lambda:
template<typename F>
std::invoke_result_t<F> foo(F&& f)
{
return f();
}
Note also that your lambda currently works only with C++23 - add the (empty) parameter list if you want this to work everywhere:
[]()->int{ return 1; }
Upvotes: 3