注意使用std::forward
首先,std::forward 用于perfect forwarding,即转发引用类型(左值或右值)。
如果您将 l-value 引用传递给 std::forward,这就是返回的内容,同样,如果传递 r-value 引用,则返回一个 r-value被退回。这与 std::move 不同,后者总是返回一个 r 值引用。还要记住命名右值引用是左值引用。
/* Function that takes r-value reference. */
void func(my_type&& t) {
// 't' is named and thus is an l-value reference here.
// Pass 't' as lvalue reference.
some_other_func(t);
// Pass 't' as rvalue reference (forwards rvalueness).
some_other_func(std::forward<my_type>(t));
// 'std::move' should be used instead as we know 't' is always an rvalue.
// e.g. some_other_func(std::move(t));
}
你也不应该在一个对象上使用std::forward 或std::move,然后你需要从中访问一些状态。被移动的对象被置于一个未指定但有效的状态,这基本上意味着你不能对它们做任何事情,除了销毁或重新分配一个状态给它们。
通过引用传递的参数std::bind?
函数std::bind 将始终复制或移动其参数。我无法从标准中找到合适的引用,但 en.cppreference.com says:
“bind 的参数被复制或移动,并且永远不会通过引用传递,除非包装在 std::ref 或 std::cref 中。”
这意味着如果你将参数作为左值引用传递,那么它是复制构造的,如果你将它作为右值引用传递,那么它就是移动构造。无论哪种方式,参数都将永远作为引用传递。
为了避免这种情况,您可以例如使用std::ref 作为可复制的引用包装器,它将在内部保留对调用站点变量的引用。
auto func = std::bind(&Foo::test, std::ref(f));
或者您可以按照您的建议简单地将指针传递给f。
auto func = std::bind(&Foo::test, &f);
然后发生的事情是std::bind 将对通过调用f 上的address-of 运算符返回的临时指针进行r 值引用。该指针将复制(因为指针不能移动)到从std::bind 返回的绑定包装对象中。即使指针本身被复制,它仍然会指向调用站点的对象,并且您将实现您想要的引用语义。
或者使用 lambda,通过引用捕获 f 并调用函数 Foo::test。恕我直言,这是推荐的方法,因为 lambda 在一般情况下比 std::bind 表达式更通用、更强大。
Foo f;
f.i = 100;
auto func = [&f] { f.test(); };
f.i = 1000;
func(); // 1000
注意:有关何时使用std::forward 的详细说明,请参阅this excellent video by Scott Meyers。