C ++ 11是否要求将此lambda声明为可变?

时间:2014-09-24 12:37:26

标签: c++ c++11 lambda visual-studio-2013 language-lawyer

考虑这个C ++ 11代码:

#include <functional>
#include <cstdlib>

template <typename F>
void test(F &&f) {
    auto foo = [f]() {
        f();
    };
    foo();
}

int main() {
    test(std::bind(std::puts, "hello"));
    return 0;
}

GCC和Clang接受此作为有效的C ++ 11代码,但Visual Studio 2013要求将lambda声明为可变(auto foo = [f]() mutable { ... })。否则我收到此错误:

  

错误C3848:类型为“const std::_Bind<true,int,int (__cdecl *const )(const char *),const char (&)[6]>”的表达式会丢失一些const-volatile限定符,以便调用“int std::_Bind<true,int,int (__cdecl *const )(const char *),const char (&)[6]>::operator ()<>(void)

Visual Studio是否正确拒绝此代码而没有可变,或者它是否有效C ++ 11?

(如果您将std::bind(std::puts, "hello")更改为std::bind(std::exit, 0),Curiously Clang会拒绝代码,因为它认为noreturn使函数类型不同;我很确定这是一个错误。)

2 个答案:

答案 0 :(得分:14)

这不是关于lambdas的。

#include <functional>
#include <cstdlib>

int main() {
  const auto x = std::bind(std::puts, "hello");
  x();
}

这被GCC接受,但被MSVC拒绝。

该标准尚不清楚这是否有效,IMO。 g的返回值std::bind有一个未指定的返回类型,g(...)有效,并根据g的cv限定符定义,但标准不实际上,任何operator()都必须可以调用const - 限定对象或引用。它强烈暗示这是有效的,因为否则对g的cv限定符的引用似乎没用,但它实际上并没有说它是有效的。

正因为如此,我认为MSVC的行为不是标准作者的意图,但它可能符合标准的要求。

答案 1 :(得分:10)

这看起来像bind的Visual Studio实现中的一个错误,返回一个只有非const函数调用运算符的类型。它应该返回一个类型,它将所有函数调用转发给绑定的函数对象,而不管它自己的cv资格。

总结C ++ 11 20.8.9.1.2中相当不透明的语言,对bind的结果的函数调用应该转发到绑定的函数对象,因此如果对该对象的调用应该允许会被允许的。因此,如果const,绑定的函数对象不可调用则会出错;但是在这里,作为一个函数指针,无论cv资格如何都可以调用它。

相关问题