operator + on Lambda

2019-06-28 07:59发布

问题:

Can anyone help me pointing out why this does not work in VS2013?

auto p = +[]() -> void { std::cout << "Hello, world!\n"; };
p();

source_file.cpp(7) : error C2593: 'operator +' is ambiguous
    could be 'built-in C++ operator+(void (__cdecl *)(void))'
    or       'built-in C++ operator+(void (__stdcall *)(void))'
    or       'built-in C++ operator+(void (__fastcall *)(void))'
    or       'built-in C++ operator+(void (__vectorcall *)(void))'

This is a legal operator to force-cast the lambda

5.1.2 Lambda expressions [expr.prim.lambda]

6 The closure type for a lambda-expression with no lambda-capture has a public non-virtual non-explicit const conversion function to pointer to function having the same parameter and return types as the closure type’s function call operator. The value returned by this conversion function shall be the address of a function that, when invoked, has the same effect as invoking the closure type’s function call operator.

How can I tell the compiler what conversion he should use?

回答1:

Apparently this is a VC++ bug. There seems to be no other way than to explicitly cast:

+ static_cast< void(*)() >( []{} ); // Empty lamba without loss of generality

Unfortunately, the magic is lost like this.



回答2:

I found a workaround for my problem. The initial problem in my first post can be solved by using a C-Cast to give the compiler a hint of what type p should be without using the unary + operator.

using ExplicitCast = void();
// valid but does not work in MSVC
auto fn = +[]() {};
// fix for MSVC
auto fn = (ExplicitCast*)[]() {};

Unfortunately this does not solve the problem when the types in the parameter list do not match (which is legal if the types are inherited). I have a function where the first parameter is different to the first parameter in my lambda. E.g:

class Foo {};
class Bar : public Foo {};

using ExplicitCast = void(Bar*);
using Function = void(Foo*);
static Function* func = nullptr;

int main()
{
    // does not work because the parameter list does not match
    // func = [](Bar*) -> void { };
    // func = +[](Bar*) -> void { };

    // does work because we first explicit cast to a function and then to the needed function.
    func = (Function*)(ExplicitCast*)[](Bar*) -> void { };

    Bar o;
    func(&o);

    return 0;
}


标签: c++ c++11 lambda