如何通过引用将功能绑定到对象? [英] How to bind function to an object by reference?

查看:83
本文介绍了如何通过引用将功能绑定到对象?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have the following code to bind a member function to an instance of the class:

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".

But the std::bind statement does not bind to f by reference. Calling func prints "100" instead of "1000" which is what I want.

但是,如果我将语句更改为采用指针,那么它将起作用.

However, If I change the statement to take a pointer it works.

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

但是根据我的理解,这是通过指针传递f,并且我认为std::bind采用r值引用Arg&&(如

But this is passing f by pointer by my understanding, and as I thought std::bind takes an r-value reference Arg&& (as shown here) how can this work?

有人可以解释一下吗?

推荐答案

使用std::forward

的注意事项

首先,std::forward用于完美转发,即转发引用类型( l值或r值).

Note on using std::forward

First of all, std::forward is meant to be used for perfect forwarding, i.e. to forward the reference type (l-value or r-value).

如果将 l值引用传递给std::forward,则返回该值,同样,如果传递了 r-value 引用,则r值返回.与std::move总是返回一个r值引用相反,它起作用.还请记住,命名 r值引用是l值引用.

If you pass an l-value reference to std::forward that is what is returned, and likewise if an r-value reference is passed then an r-value is returned. This works as opposed to std::move that will always return an r-value reference. Also remember that named r-value references are l-value references.

/* 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.移出的对象处于未指定状态,但处于有效状态,这基本上意味着您无法对它们执行任何操作,除非销毁或重新为其分配状态.

Also you should never use std::forward or std::move on an object that you afterwards need to access some state from. Objects that are moved from are put in an unspecified but valid state, which basically means that you cant do anything with them except destroy or reassign a state to them.

函数std::bind将始终复制或移动其参数.我从标准中找不到合适的引用,但 en.cppreference.com说:

The function std::bind will always copy or move its arguments. I could not find an appropriate citation from the standard but en.cppreference.com says:

要绑定的参数将被复制或移动,除非包装在std :: ref或std :: cref中,否则绝对不会通过引用传递."

这意味着,如果您将参数作为左值引用传递,则它是副本构造的;如果您将其作为右值引用传递,则它是搬动.无论哪种方式,参数都永远不会作为引用传递.

This means that if you pass the argument(s) as an l-value reference then it is copy constructed, and if you pass it as an r-value reference then it is move constructed. In either way the argument(s) will never be passed as references.

要避免这种情况,您可以例如使用 std::ref 作为可复制的参考包装,它将在内部保留参考到呼叫站点上的变量.

To circumvent this you can e.g. use std::ref as a copyable reference wrapper that will internally keep a reference to the variable at the call site.

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

或者您可以按照您的建议简单地将指针传递给f.

Or you could simply pass a pointer to f as you suggest.

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

然后发生的是,std::bind将对通过调用f的address-of运算符返回的临时指针进行r值引用.该指针将被复制(因为指针无法移动)到std::bind返回的绑定包装对象中.即使指针本身已被复制,它仍将指向调用站点上的对象,您将获得所需的引用语义.

What happens then is that std::bind will take an r-value reference to the temporary pointer returned from calling the address-of operator on f. This pointer will be copied (as pointers can't be moved) into the bound wrapper object returned from std::bind. Even though the pointer itself is copied, it will still point to the object at the call site and you will achieve the reference semantics you wanted.

或者使用 lambda 来通过引用捕获f并调用函数Foo::test.这是恕我直言,因为通常情况下lambda比std::bind表达式更具通用性和功能,因此是推荐的方法.

Alternatively use a lambda that captures f by reference and calls the function Foo::test. This is IMHO the recommended approach as lambdas are more versatile and powerful than std::bind expressions in the general case.

Foo f;
f.i = 100;
auto func = [&f] { f.test(); };
f.i = 1000;
func(); // 1000

注意:有关何时使用std::forward的详细说明,请参见

Note: for a good explanation of when to use std::forward see this excellent video by Scott Meyers.

这篇关于如何通过引用将功能绑定到对象?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆