What is this compiler error when using a lambda as

2019-04-10 05:05发布

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?

2条回答
聊天终结者
2楼-- · 2019-04-10 05:25

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.

查看更多
【Aperson】
3楼-- · 2019-04-10 05:35

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.

查看更多
登录 后发表回答