可变参数模板中的Lambda表达式

28

使用 Microsoft Visual C++ 2013 (12.0) 时,我在可变参数模板中的构造函数中使用lambda表达式时遇到了编译时错误。我已经将其简化为下面所示(请查看带有error注释的行)。看起来这是一个12.0版本的bug,在14.0中不存在。我没有尝试其他版本。是否有关于此bug的文档,例如发行说明,阐明了此bug发生的条件,并说明已经明确修复了它?

#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;
}

编辑/更新: MSVC 2013编译器似乎存在这个错误,最新版本已经修复了。GCC和clang编译器没有显示任何错误。


2
我刚刚添加了 #include <functional>,然后它就编译通过了。我使用的是 Microsoft Visual Studio Community 2015 版本 14.0.25431.01 Update 3。 - wally
6
由于gcc和clang都能够接受该代码(演示),我认为这是msvc的一个错误(尤其是在使用您的模板和可变参数模板测试中)。 - Jarod42
1
最新版本的MSVC似乎可以轻松编译它。我猜你正在寻找2015年版本的解决方法? - AndyG
1
@MichaelGunter:我在2013年的版本中也能重现这个问题。一个解决方法是使用花括号初始化:MyClass a{[] {}}; 这对你来说可行吗?老实说,这是编译器的缺陷,所以除非你很幸运地让Stephen Lavavej看到这个问题,否则没有真正的解释为什么会发生这种情况。 - AndyG
5
据我所知,编译器识别了lambda表达式(参见错误C2440的消息)。因此可能会发生以下两种情况之一:A)编译器试图将lambda传递给MyClass的构造函数,但它错误地将其识别为使用int。或者B)编译器无法将MyClass视为类型说明,因此推断a是一个int,然后不允许使用lambda对其进行初始化。后者似乎更有可能。 - Michael Gunter
显示剩余9条评论
2个回答

1
我不能确定这是否是一个bug,过去微软并不急于采用最新的C++标准,它落后于GCC和CLang两个步骤,而且很容易了解到没有人在一次编译器更新中实现整个标准。例如,std库中的一些内容可能只被部分实现,比如Visual Studio通常在std::experimental命名空间下实现新功能(例如VS2013的文件系统),但是像编译器词元这样的东西就不能通过这种方式添加。
关于标准兼容性的常见信息,建议使用编译器支持文章https://en.cppreference.com/w/cpp/compiler_support/11(MSVC表示_MSC_VER定义),更详细的信息可以在https://learn.microsoft.com/en-us/cpp/overview/visual-cpp-language-conformance中找到有关Visual Studio的信息。在这里https://en.wikipedia.org/wiki/Microsoft_Visual_C++#Internal_version_numbering,您可以找到与相关Visual Studio版本一起的_MSC_VER版本,源代码在https://learn.microsoft.com/en-us/cpp/preprocessor/predefined-macros中。
根据那些文章,我认为你的问题在于“可变参数模板”和“Lambda表达式”之间,这两者都得到了Visual Studio 19.0的完全支持。在维基百科中搜索_MSC_VER 1900,意味着Visual Studio 2015(根据微软的文章,如果要精确的话,是更新2)。

0

vs2015可以正常编译,因为vs2015完全支持c++11标准,你可以考虑升级你的vs


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接