Why would one want to put a unary plus (+) operator in front of a C++ lambda?

Viewed 929

I found out that in C++ we can use + in lambda function +[]{} Example from the article:

#include <iostream>
#include <type_traits>
int main()
{
    auto funcPtr = +[] {};
    static_assert(std::is_same<decltype(funcPtr), void (*)()>::value);
}

The main idea of + sign in lambda

You can force the compiler to generate lambda as a function pointer rather than closure by adding + in front of it as above.

But what are advantages of using '+' in lambda? Could you please provide example or link me to the explanation?

2 Answers

It's not a feature of lambda and more is a feature of implicit type conversion.

What happens there is stemming from the fact that a captureless lambda can be implicitly converted to a pointer to function with same signature as lambda's operator(). +[]{} is an expression where unary + is a no-op , so the only legal result of expression is a pointer to function.

In result auto funcPtr would be a pointer to a function, not an instance of an object with anonymous type returned by lambda expression. Not much of advantage in provided code, but it can be important in type-agnostic code, e.g. where some kind of decltype expression is used. E.g.

#include <type_traits>

void foo(int);

template<class T>
struct is_foo : std::is_same<T, decltype(&foo)> {};

int main()
{
    auto foo1 = +[](int)->void {};
    auto foo2 = [](int)->void {};
    static_assert(is_foo<decltype(foo1)>::value, "foo1 is not like foo");
    static_assert(is_foo<decltype(+foo2)>::value, "+foo2 is not like foo");
    static_assert(is_foo<decltype(foo2)>::value, "foo2 is not like foo"); 
}  

Note that you can do same with foo: std::is_same<T, decltype(+foo)> {};

Albeit some platforms may not support that, because they inherently may have a variety of function pointers with different calling convention and the expression will be ambiguous.

One advantage to use function pointer against lambda in template might be to reduce the number of template instantiation.

template <typename F>
void f(F func) { func(); }


int main()
{
    f([](){});  // f<lambda_1>
    f([](){});  // f<lambda_2>
    f(+[](){}); // f<void(*)()>
    f(+[](){}); // f<void(*)()>
}
Related