Kwan
Kwan

Reputation: 199

how to deduce return type from lambda?

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

Answers (2)

songyuanyao
songyuanyao

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

Useless
Useless

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

Related Questions