将 std::bind 创建的对象传递给函数的正确方法是什么?

mic*_*ael 5 c++ pass-by-reference functor stdbind auto

假设我想传递一个通过std::bind引用 funktion 创建的函数对象:

void myCallback(int i, int j)
{
    std::cout << "toCall , i=" << i << " j=" << j;
}

void worker(std::function<void(int)> & callback)
{
    callback(111);
}

int main(int argc, char** argv)
{
    auto foo = std::bind(myCallback, std::placeholders::_1, 222);
    worker(foo);
}
Run Code Online (Sandbox Code Playgroud)

这不能编译

编译器错误

严重性代码说明项目文件行抑制状态错误 C2664 'void worker(std::function &)': 无法将参数 1 从 'std::_Binder &,int>' 转换为 'std::function &' asn1test_1 D:.. ...\asn1test_1.....cpp 302

然而,按值传递是有效的:

void worker(std::function<void(int)> callback)
{
    callback(111);
}
Run Code Online (Sandbox Code Playgroud)

当我避免使用“ auto”并改为使用

std::function<void(int)> foo = std::bind(myCallback, std::placeholders::_1, 222);
Run Code Online (Sandbox Code Playgroud)

它既可以通过引用传递,也可以通过值传递。

Q1:为什么会有这种行为?

std::bindQ2:将创建的对象传递给函数的“正确”方式或数据类型是什么?

Nat*_*ica 5

std::bind不返回 a std::function,至少不需要这样做。当你这样做时

auto foo = std::bind(myCallback, std::placeholders::_1, 222);
worker(foo);
Run Code Online (Sandbox Code Playgroud)

foo不是 astd::function并且worker需要对 a 的非常量引用std::function,因此编译器会出错。如果你切换worker

void worker(const std::function<void(int)> & callback)
Run Code Online (Sandbox Code Playgroud)

那么您将拥有一个 const 引用,并且可以将其绑定到转换foo为 astd::function将产生的临时对象。


我还想指出,由于我们有 lambda,尤其是泛型,所以std::bind实际上并不需要。将更改保留给工人,您可以改为foo

auto foo = [](auto var){ return myCallback(var, 222); };
Run Code Online (Sandbox Code Playgroud)


Rem*_*eau 5

std::bind()不返回 a ,而是返回可转换为 a 的std::function实现定义类型。std::function

worker()将其callback参数作为非常量引用时,会阻止编译器执行任何隐式转换,因为非常量引用无法绑定到临时对象。该引用需要std::function事先显式创建一个实际对象,例如:

std::function<void(int)> foo = std::bind(myCallback, std::placeholders::_1, 222);
worker(foo);
Run Code Online (Sandbox Code Playgroud)

更改worker()为按值或常量引用获取其参数,允许编译器为您执行隐式转换,因此您可以按原样callback传递结果,编译器将为您创建一个临时值。std::bind()std::function

  • @ChrisDodd 如果“bind”确实返回了“std::function”,那么代码就可以工作。OP 正在传递 `foo`,它将是一个左值 `std::function`。 (2认同)

Nut*_*ker 1

它应该是:

void worker(std::function<void(int)> const& callback) {
    callback(111);
}
Run Code Online (Sandbox Code Playgroud)

因为这样就可以进行从foo临时对象的隐式转换。std::function

  • 实际上,问题在于您无法将对未命名临时变量的引用作为非常量左值引用传递。 (2认同)