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

Sam*_*des 27 c++ lambda language-lawyer c++11 visual-studio-2013

考虑一下这个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;
}
Run Code Online (Sandbox Code Playgroud)

GCC和Clang接受此作为有效的C++ 11代码,但Visual Studio 2013要求将lambda声明为mutable(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?

(好奇Clang拒绝代码,如果你明显改变std::bind(std::puts, "hello"),std::bind(std::exit, 0)因为它认为noreturn使函数类型不同;我很确定这是一个错误.)

小智 14

这不是关于lambdas的.

#include <functional>
#include <cstdlib>

int main() {
  const auto x = std::bind(std::puts, "hello");
  x();
}
Run Code Online (Sandbox Code Playgroud)

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

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

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


Mik*_*our 10

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

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