4

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?

0

3 Answers 3

3

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.

Sign up to request clarification or add additional context in comments.

Comments

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.

5 Comments

Oh I standardized it now, thanks for pointing that out because it could confuse things. VS2012 accepts the no-inputs syntax just fine though.
@Timothy: The parameter list is optional, the smallest valid lambda expression is []{}. This is not the problem.
@Xeo I know, originally I was omitting the parameter list as is valid. But it was attracting attention as the possible source of the error so I figured I'd use the syntax people are more familiar with so as not to distract.
@Anthony When you say "Both version compile with GCC" do you mean that you've taken the code I provided and successfully built it? If so, that's important news for me, because that probably means this is a VS2012 compiler error. I don't know how to run GCC to check myself - if you know it works using GCC that would be a huge help for me! -- I'm actually downloading GCC now so I can try to figure out how to do this sort of test on my own for the future.
@TimothyShields: Yes, sorry I wasn't more clear. With or without the empty argument list it compiled fine on Linux.
0

I do not know if that behavior comply with the standard but with VC++ 2019 that error happen only with the option /permissive-, then when the strict mode is on.

Nevertheless here is how to solve the problem, by just casting the lambda with a reference type:

template <typename FUNC>
void f(FUNC& o){}

int main()
{
    f((std::function<void()>&)[](){});
    // or also:
    auto func = [](){};
    f(func);
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.