How to bind function to an object by reference?

后端 未结 2 625
遇见更好的自我
遇见更好的自我 2020-12-28 09:04

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


        
相关标签:
2条回答
  • 2020-12-28 09:17

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

    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));
    }
    

    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.

    Arguments passed by reference to std::bind?

    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:

    "The arguments to bind are copied or moved, and are never passed by reference unless wrapped in std::ref or 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.

    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));
    

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

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

    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.

    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
    

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

    0 讨论(0)
  • 2020-12-28 09:19

    Arguments taken by std::bind are actually Universal references, which can bind to both lvalues and rvalues. You cannot just pass value to std::bind, since that will copy it.

    To pass the reference to the std::bind you can use std::ref:

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

    LIVE DEMO

    0 讨论(0)
提交回复
热议问题