我有一个函数模板,该模板接受某种可调用类型的参数,并使用std::bind
来创建一个新的可调用对象,并为原始可调用对象预定义参数值。我已经使用转发参考参数和std::forward
编写了它,如下所示:
template <typename F>
auto make_example_caller(F &&f) {
return std::bind(std::forward<F>(f), 123, 456, 789);
}
cppreference documentation for std::bind
说绑定对象“持有从std::decay<F>::type
构造的类型std::forward<F>(f)
的成员对象”。由于std::bind
将函数转发给其内部数据成员,因此在我自己的代码中将相同的函数转发给std::bind
调用似乎是合理且适当的。
但是,尚不清楚带来什么好处。如果F
是引用类型,则std::decay
删除引用,因此绑定对象将存储其自己的可调用类型的实例。如果F
是一个右值引用,则该实例将被构造为移动;如果F
是一个左值,则该实例将被构造为副本,如果我这样编写函数,则可以获得相同的结果:
template <typename F>
auto make_example_caller(F f) { // Note, no &&
return std::bind(std::move(f), 123, 456, 789); // move, not forward
}
现在,根据调用函数的方式,将通过移动或复制来初始化函数自己的f
参数,但是无论哪种方式,我现在都有自己的函数对象实例,可以将其移入绑定中对象。
后一种方法似乎更简单,但是我想知道是否遗漏了某些东西-尤其是因为相同的推理将适用于std::bind
本身,但是它需要F&&
并将其转发,而不是采用F
(按值)并将其移动。这样做有缺点吗?我没看到的东西?
答案 0 :(得分:6)
使用转发参考和std::forward
,您可以避免创建额外的对象。
如果不使用转发引用,则涉及三个对象:
f
,使用适当的copy或move构造函数构造如果您将转发引用与std::forward
一起使用,则将消除第二个引用。将仅创建两个对象:
虽然移动构造对象 可能比复制构造便宜(取决于类型),但它仍会带来一些无法完全完善的开销。