使用std :: forward代替std :: move初始化对象有什么好处?

Wyz*_*a-- 9 c++ c++17

我有一个函数模板,该模板接受某种可调用类型的参数,并std::bind用于为原始可调用对象创建一个带有预定义参数值的新可调用对象。我已经使用转发参考参数和编写了它std::forward,如下所示:

template <typename F>
auto make_example_caller(F &&f) {
  return std::bind(std::forward<F>(f), 123, 456, 789);
}
Run Code Online (Sandbox Code Playgroud)

cppreference文档std::bind说绑定的对象“持有std::decay<F>::type从中构造的类型的成员对象std::forward<F>(f)。由于std::bind将函数转发到其内部数据成员,因此std::bind用我自己的代码将同一函数转发到调用似乎是合理且适当的。

但是,尚不清楚带来什么好处。如果F是引用类型,则std::decay删除引用,因此绑定对象将存储其自己的可调用类型的实例。如果F是右值引用,则该实例将被构造为move;如果是F左值,则将其构造为副本;如果我编写如下函数,则可以得到相同的结果:

template <typename F>
auto make_example_caller(F f) {  // Note, no &&
  return std::bind(std::move(f), 123, 456, 789);  // move, not forward
}
Run Code Online (Sandbox Code Playgroud)

现在,根据调用函数的f方式,可以通过移动或复制来初始化函数自己的参数,但是无论哪种方式,我现在都有自己的函数对象实例,可以将其移入绑定对象。

后一种方法似乎更简单,但是我想知道是否遗漏了某些东西-尤其是因为相同的推理将适用于std::bind它自身,但是它需要F&&并转发它,而不是F按值来获取并移动它。这样做有缺点吗?我看不到的东西?

Mil*_*nek 6

使用转发引用,std::forward您可以消除额外对象的创建。

如果不使用转发引用,则涉及三个对象:

  1. 呼叫者的原始对象
  2. 函数参数f,根据需要使用copy或move构造函数构造
  3. 绑定对象的内部对象,该对象由move构造函数构造

如果您将转发参考与一起使用std::forward,则消除第二个参考。将仅创建两个对象:

  1. 呼叫者的原始对象
  2. 绑定对象的内部对象,该对象使用适当的copy或move构造函数构造

尽管移动构造一个对象可能比复制构造便宜(取决于类型),但它仍然会带来一些无法完全转移的开销。