我有以下代码将成员函数绑定到类的实例:
class Foo {
public:
int i;
void test() {
std::cout << i << std::endl;
}
};
int main() {
Foo f;
f.i = 100;
auto func = std::bind(&Foo::test, std::forward<Foo>(f));
f.i = 1000;
func();
}
但是std::bind
语句没有通过引用绑定到f
。拨打func
打印&#34; 100&#34;而不是&#34; 1000&#34;这就是我想要的。
但是,如果我更改语句以获取指针就可以了。
auto func = std::bind(&Foo::test, &f);
但是我的理解是通过指针传递f
,并且我认为std::bind
采用r值引用Arg&&
(如图here所示)这怎么可能工作?
有人可以解释一下吗?
答案 0 :(得分:14)
std::forward
首先,std::forward
用于perfect forwarding,即转发引用类型(l值或r值)。
如果您将 l-value 引用传递给返回的std::forward
,同样如果传递了 r-value 引用,那么r -value返回。这与std::move
相反,它始终返回r值引用。还要记住,名为的r值引用是l值引用。
/* 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:
“绑定的参数被复制或移动,除非包含在std :: ref或std :: cref中,否则永远不会通过引用传递。”
这意味着如果您将参数作为l值引用传递,那么它是复制构造,如果您将其作为r值引用传递,那么它是移动构造。无论哪种方式,参数永远不会作为参考传递。
为了避免这种情况你可以例如使用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
。这是恕我直言的推荐方法,因为在一般情况下,lambdas比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。
答案 1 :(得分:5)
std::bind
所采用的参数实际上是Universal references,它可以绑定到左值和右值。您不能只将值传递给std::bind
,因为这会复制它。
要将参考传递给std::bind
,您可以使用std::ref
:
auto func = std::bind(&Foo::test, std::ref(f));