首页 > 解决方案 > 为什么这个不正确的 std::function 初始化使用 MSVC 编译?

问题描述

今天遇到一个有趣的问题,由我自己的错字开始。我创建了一个 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 编译器中的错误吗?

标签: c++c++11gccvisual-c++

解决方案


总之:这不是编译器错误。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参数。简单函数指针a,不能设置为指向fn,因为参数的类型不同(intvs short)。但是,std::function允许这样做,所以b可以设置为指向fn

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

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


推荐阅读