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

tex*_*uce 15 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();
}
Run Code Online (Sandbox Code Playgroud)

但该std::bind声明并未f通过引用绑定.调用func打印"100"而不是"1000"这是我想要的.

但是,如果我更改语句以获取指针它是否有效.

auto func = std::bind(&Foo::test, &f);
Run Code Online (Sandbox Code Playgroud)

但是,这是通过f由指针我的理解,因为我认为std::bind需要一个R值的参考Arg&&(如图所示这里)如何工作的呢?

有人可以解释一下吗?

Snp*_*nps 19

使用注意事项 std::forward

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

如果将l值引用传递给std::forward返回的值,同样如果传递了r 引用,则返回r值.与此相反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));
}
Run Code Online (Sandbox Code Playgroud)

此外,您永远不应该使用std::forwardstd::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));
Run Code Online (Sandbox Code Playgroud)

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

auto func = std::bind(&Foo::test, &f);
Run Code Online (Sandbox Code Playgroud)

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

或者使用通过引用捕获的lambdaf并调用该函数Foo::test.这是恕我直言的推荐方法,因为lambdas比std::bind一般情况下的表达更通用和更强大.

Foo f;
f.i = 100;
auto func = [&f] { f.test(); };
f.i = 1000;
func(); // 1000
Run Code Online (Sandbox Code Playgroud)

注意:有关何时使用的详细说明,std::forward请参阅Scott Meyers的精彩视频.


Raf*_*zuk 5

所采用的参数std::bind实际上是通用引用,它可以绑定到左值和右值.你不能只传递值std::bind,因为那会复制它.

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

auto func = std::bind(&Foo::test, std::ref(f));
Run Code Online (Sandbox Code Playgroud)

LIVE DEMO