如何通过引用将函数绑定到对象?

时间:2014-10-03 21:39:50

标签: c++ stdbind

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

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所示)这怎么可能工作?

有人可以解释一下吗?

2 个答案:

答案 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::forwardstd::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));

LIVE DEMO