28

Using Microsoft Visual C++ 2013 (12.0), I am encountering compile-time errors when using a lambda in a constructor in a variadic template. I have managed to boil it down as shown below (see the lines with the error comments). It appears to be a bug in 12.0 that is not present in 14.0. I haven't tried other versions. Is there any documentation on this bug, perhaps in the form of a release note that clarifies the conditions under which this bug occurs and which states that it has been explicitly fixed?

#include <functional>

// a simple method that can take a lambda
void MyFunction(const std::function<void()>& f) {}

// a simple class that can take a lambda
class MyClass
{
public:
    MyClass(const std::function<void()>& f) {}
};

// non-templated test
void test1()
{
    MyFunction([] {}); // OK
    MyClass([] {}); // OK
    MyClass o([] {}); // OK
}

// non-variadic template test
template<typename T>
void test2()
{
    MyFunction([] {}); // OK
    MyClass([] {}); // OK
    MyClass o([] {}); // OK
}

// variadic template test
template<typename... T>
void test3()
{
    MyFunction([] {}); // OK
    MyClass([] {}); // OK
    MyClass a([] {}); // error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
                      // error C2440: 'initializing' : cannot convert from 'test3::<lambda_12595f14a5437138aca1906ad0f32cb0>' to 'int'

    MyClass b(([] {})); // putting the lambda in an extra () seems to fix the problem
}

// a function using the templates above must be present
int main()
{
    test1();
    test2<int>();
    test3<int, int, int>();
    return 1;
}

Edit/Update: MSVC 2013 compiler seem to have this bug, latest versions fixed that. GCC and clang compilers don't show any error.

Jishan Shaikh
  • 1,572
  • 2
  • 13
  • 31
Michael Gunter
  • 12,528
  • 1
  • 24
  • 58
  • 2
    I just added `#include ` and it compiled. I used Microsoft Visual Studio Community 2015 Version 14.0.25431.01 Update 3 – wally Oct 31 '16 at 21:47
  • Weird. I have `#include ` in my code (forgot to include in copy-paste), but it still complains for me. – Michael Gunter Oct 31 '16 at 21:51
  • 6
    As gcc&clang accept the code ([Demo](http://coliru.stacked-crooked.com/a/86fa0b4c990af350)). I would say msvc bug (even more with your template and variadic template test). – Jarod42 Oct 31 '16 at 22:13
  • Function signature confusion somehow? Like most vexing parse? – Yakk - Adam Nevraumont Nov 01 '16 at 00:04
  • 1
    Latest version of MSVC appears to compile it no problem. I suppose you're looking for a workaround for your version of 2015 then? – AndyG Jan 11 '17 at 19:48
  • 1
    Additionally, Visual Studio 2015 Update 3 appears to compile it. Are you able to update? – AndyG Jan 11 '17 at 19:52
  • @AndyG: I have been using Update 3 since the day it came out (well before this post). However, I cannot repro on 2015 today. Maybe my mistake on reporting the version numbers I'm using. – Michael Gunter Jan 11 '17 at 19:53
  • 1
    @MichaelGunter: I can repro in 2013. One thing that fixed it was using braced initialization: `MyClass a{[] {}};` Is that a feasible solution for you? Honestly it's a compiler shortcoming, so no real explanation about why it happens unless you get lucky and Stephen Lavavej sees this. – AndyG Jan 11 '17 at 20:00
  • @AndyG: I've had a workaround place since day 1. (See `// putting the lambda in an extra () seems to fix the problem`.) I was hoping someone could shed some light on what the compiler bug is. Specifically, where exactly is it inferring a default-int? – Michael Gunter Jan 11 '17 at 20:20
  • @MichaelGunter: That's what happens when the compiler encountered an undefined type until Visual Studio 2015... it just assumed an int (and then usually bombed out for other reasons). What's probably happening is that the `std::function` class is attempting to construct itself with an instance of a lambda, but something went wrong inside of the compiler and what you wrote was not parsed correctly as a valid type. – AndyG Jan 11 '17 at 20:34
  • @AndyG: I understand `default-int` in general. What I don't understand is which part of the code is the specific point at which it thinks a type name is missing. – Michael Gunter Jan 11 '17 at 20:35
  • 5
    From what I can tell, the compiler recognizes the lambda (see message of error C2440). So there must be one of two things happening: A) The compiler is trying to pass the lambda into the constructor of `MyClass`, which it has erroneously identified as taking an `int`. Or B) the compiler fails to see `MyClass` as the type specification, thereby inferring `a` to be an `int`, and then disallowing the lambda to be used to initialize it. The latter seems more probable. – Michael Gunter Jan 11 '17 at 20:44
  • I can't reproduce the issue, but what about `MyClass a([](){});` ? – GaspardP Jan 18 '17 at 03:06
  • Might trying adding explicit modifier to the ctor signature., my guess is that it's trying to cast it. – Tom Kerr Sep 13 '19 at 02:16

2 Answers2

1

I can't say is that bug or not, back days Microsoft was not so eager to latest C++ standards, it was two steps behind GCC and CLang, and it's not a surprise to know that no-one implement a whole standard in one compiler update. Some stuff from std library may be partially implemented, for example Visual Studio usually implements new features under std::experimental namespace (filesystem for VS2013), but something like compiler lexemes can't be added that way.

For common information about standard compatibility I suggest to use compiler support article https://en.cppreference.com/w/cpp/compiler_support/11 (MSVC means _MSC_VER definition) and https://learn.microsoft.com/en-us/cpp/overview/visual-cpp-language-conformance more for detailed information about Visual Studio. Here https://en.wikipedia.org/wiki/Microsoft_Visual_C++#Internal_version_numbering you can find _MSC_VER version along with related Visual Studio version, source is https://learn.microsoft.com/en-us/cpp/preprocessor/predefined-macros.

Based on those articles I believe that your problem lays in between "Variadic templates" and "Lambda expression" both are fully supported from Visual Studio 19.0, searching _MSC_VER 1900 in wiki that means Visual Studio 2015 (Update 2, if to be precise according to Microsoft article).

Liastre
  • 1,281
  • 11
  • 29
0

vs2015 can be compiled normally, because vs2015 can fully support the c++11 standard, you can consider upgrading your vs

henry3695
  • 19
  • 1