【问题标题】:How to bind function to an object by reference?如何通过引用将函数绑定到对象?
【发布时间】:2014-11-28 23:58:07
【问题描述】:

我有以下代码将成员函数绑定到类的实例:

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&amp;&amp;(如图所示here)这怎么能工作?

有人可以解释一下吗?

【问题讨论】:

  • 你可以使用 lambdas 吗? auto func = [&amp;](){f.test();}; func();。这应该通过引用捕获f 的值。

标签: c++ stdbind


【解决方案1】:

注意使用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::forwardstd::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

【讨论】:

  • 不错的答案。 +1 特别是视频链接!
【解决方案2】:

std::bind 采用的参数实际上是Universal references,它可以绑定到左值和右值。您不能只将值传递给std::bind,因为这会复制它。

要将引用传递给std::bind,您可以使用std::ref

auto func = std::bind(&Foo::test, std::ref(f));

LIVE DEMO

【讨论】:

    猜你喜欢
    • 2016-06-26
    • 2017-12-05
    • 2020-11-07
    • 1970-01-01
    • 2012-02-03
    • 2013-11-13
    • 2023-03-28
    • 1970-01-01
    • 2015-09-20
    相关资源
    最近更新 更多