What is this compiler error when using a lambda as

2019-04-10 05:35发布

问题:

Edit:

This has been reported as a VS2012 C++ compiler bug on Microsoft Connect (link).

Nov. 11, 2014: Microsoft has responded saying the fix for this bug should show up in the next major release of Visual C++.


I've been struggling with a VS2012 compiler error message I don't understand, so I trimmed down the problem to what seems like the bare minimum.

I'm building the following main.cpp using VS2012:

#include <utility>

template <typename T>
struct A
{
    T x;
    A(A&& other) : x(std::move(other.x)) { }
    A(T&& x) : x(std::move(x)) { }
};

template <typename T>
A<T> build(T&& x)
{
    return A<T>(std::move(x));
}

int main(int argc, char* argv[])
{
    auto f = []()
    {
        return build([](){}); //error here
    };
    return 0;
}

The salient point is that I'm trying to use a lambda as the template type T of the build function. The error message I get is:

1>  main.cpp
1>C:\test\main.cpp(21): error C2664: 'A<T>::A(A<T> &&)' : cannot convert parameter 1 from 'A<T>' to 'A<T> &&'
1>          with
1>          [
1>              T=void (__cdecl *)(void)
1>          ]
1>          and
1>          [
1>              T=main::<lambda_c3c618d445b3cb24eede9bf304860ad7>::()::<lambda_4240e93016e3e420ff8383c9350ae130>
1>          ]
1>          and
1>          [
1>              T=void (__cdecl *)(void)
1>          ]
1>          Reason: cannot convert from 'A<T>' to 'A<T>'
1>          with
1>          [
1>              T=main::<lambda_c3c618d445b3cb24eede9bf304860ad7>::()::<lambda_4240e93016e3e420ff8383c9350ae130>
1>          ]
1>          and
1>          [
1>              T=void (__cdecl *)(void)
1>          ]
1>          No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called

I've done my research and looked up the page for the error message (link), but I still can't figure out what the problem is. Could you please explain this compiler error?


edit

Something is definitely weird here. If I change the code in main to look like this:

auto f = []()
{
    int* n = new int(0);
    auto g = [=](){ return *n; };
    *n++;
    return build<decltype(g)>(std::move(g));
};

I get an error message suggesting that T=int (__cdecl *)(void) in the call to build - which would mean that decltype(g) is giving me a function pointer? Huh? I'm capturing a pointer by value and then modifying it afterwards - shouldn't it have to create a functor - and one that has no cast to function pointer? Maybe I'm not understanding something.

See related: Lambda expressions : n3290 draft


Also, if this is a bug in the VS2012 compiler, can you think of a workaround?

回答1:

I can confirm that using GCC (on linux), this code compiles just fine. So I'd say that VisualStudio seems to be the source of the error.



回答2:

I don't have Windows or Visual Studio to verify, nor do I have much experience with lambda functions in C++, but perhaps you need to include the (albeit empty) parameter list in the function? i.e. change line 21 to

return build([](){});

Both versions compile with GCC, but perhaps Visual Studio is a bit more picky.

The other question I might have is whether the lambda function you're defining at line 24 will work out since its return value involves the lambda function you're defining inside the function itself.