如何通过引用将函数绑定到对象
How to bind function to an object by reference?
我有以下代码将成员函数绑定到类的实例:
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
会打印"100"而不是我想要的"1000"。
但是,如果我将语句更改为使用指针,它就会起作用。
auto func = std::bind(&Foo::test, &f);
但根据我的理解,这是通过指针传递f
,正如我所认为的,std::bind
采用r值引用Arg&&
(如图所示),这怎么能工作呢?
有人能解释一下吗?
关于使用std::forward
的注意事项
首先,std::forward
用于完美转发,即转发参考类型(l值或r值)。
如果将l-value引用传递给std::forward
,即返回的值,同样,如果传递r-valuereference,则返回r-value。这与总是返回r值引用的std::move
相反。还要记住,命名的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说:
"要绑定的参数被复制或移动,除非包装在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
上的运算符地址返回的临时指针进行r值引用。此指针将被复制(因为指针无法移动)到从std::bind
返回的绑定包装器对象中。即使指针本身被复制,它仍然会指向调用站点上的对象,并且您将实现所需的引用语义。
或者使用lambda,它通过引用捕获f
并调用函数Foo::test
。这是IMHO推荐的方法,因为在一般情况下,lambda比std::bind
表达式更通用、更强大。
Foo f;
f.i = 100;
auto func = [&f] { f.test(); };
f.i = 1000;
func(); // 1000
注意:有关何时使用std::forward
的详细说明,请参阅Scott Meyers的这段精彩视频。
std::bind
采用的参数实际上是通用引用,可以绑定到左值和右值。您不能只将值传递给std::bind
,因为这会复制它
要将引用传递到std::bind
,可以使用std::ref
:
auto func = std::bind(&Foo::test, std::ref(f));
现场演示
- 有没有办法将重载的类函数绑定到函数对象?
- Opengl 3/4 : 我可以将相同的缓冲区对象绑定到不同的目标吗?
- 未定义的对象(〔basic.life〕/8):为什么允许引用重新绑定(和常量修改)
- 如何发送通过绑定到函数/方法创建的函数对象?
- 与类而非对象绑定的可变变量
- 为什么临时对象可以绑定到常量引用?
- 无法在 QML/C++ 中使用绑定对象初始化 UI
- 实现功能对象绑定而无需使用C 11
- 是否可以将匿名 lambda 函数绑定到对象以允许 lambda 中的代码访问对象的成员?
- RValue 引用在将其绑定(非指针)对象分配给另一个指针后是否会删除该对象?
- 如何将Boost ::函数对象与所有参数绑定
- 将临时对象绑定到常量引用
- 为什么免费存储区中对象的生存期绑定到范围
- C++17:是编译器为(静态存储持续时间)const引用绑定创建的可修改的临时对象(和存储)
- opengl:两个不同的矢量可以绑定到同一个顶点数组对象吗
- 为每个对象绑定不同的纹理
- std ::将参数绑定到没有对象的情况下的成员函数
- C++保存绑定对象并在ASIO之后使用它
- BGL:没有默认构造函数的绑定对象
- 如何在Qt中删除绑定对象