为什么使用MSVC编译此错误的std :: function初始化?

时间:2019-02-20 20:17:14

标签: c++ c++11 gcc visual-c++

今天由我自己的错字开始引起一个有趣的问题。我创建了一个lambda,它接受了对结构的引用,并将其错误地设置为按值接收其参数的std :: function。

这是一个更简洁的版本:

#include <functional>

struct InputStruct
{
    int i;
    InputStruct(): i(1){}
};

void function_rcv(std::function<bool(InputStruct)> & func_ref)
{
    InputStruct in;
    func_ref(in);
}


int main()
{
    std::function<bool(InputStruct)> my_func = [](InputStruct & in)->bool{return in.i==1;};
    function_rcv(my_func);
}

使用godbolt进行检查显示,此操作可以使用MSVC成功编译,但是对于Clang和GCC均失败。

有趣的是,使用原语而不是结构在所有三个编译器上编译失败。

这是MSVC编译器中的错误吗?

1 个答案:

答案 0 :(得分:6)

总结:它不是编译器错误。 MSVC接受此代码是因为其默认的不符合行为,但可以通过开关使其符合标准。

首先,我需要阐明std::function的一个方面:它接受一个函数(通常为 Callable ),该函数的签名不是完美匹配,但是参数可以被转换。考虑:

using intFn = void (int);
void fn(short);

intFn *a = fn;               // doesn't compile
std::function<intFn> b = fn; // compiles!

此处,intFn是具有int参数的函数类型,而函数fn具有short参数的函数类型。由于参数的类型不同(afn),因此无法将简单函数指针int设置为指向short。但是,std::function允许这样做,因此可以将b设置为指向fn

在您的示例中,std::function具有按值的InputStruct参数,而lambda具有非常量左值引用InputStruct &。当std::function std::forward作为其参数时,它成为一个xvalue,不能绑定到lambda的lvalue参考参数。这就是为什么符合标准的编译器不接受此代码的原因。

MSVC为什么接受此代码?因为默认情况下它具有不一致的行为:它允许将类临时变量(和xvalues)绑定到非const左值引用。您可以使用/Zc:referenceBinding(或较旧的/Za选项)禁用此行为。如果使用此开关,则MSVC会拒绝您的示例。