使用 std::bind 和 std::function 将 class 成员函数用作另一个 class 成员例程的回调

Using std::bind and std::function to use a class member function as callback for another class member routine

这可能之前已经探索过,但我不确定它是如何工作的,以及在我的特定情况下应该如何..

基本上我有一个 class,回调定义为:

class Foo
{
    public:
    using someCallbackName = std::function<void(int)>;
    void someFunc();
    Foo(int, someCallBackName);
    private : 
    someCallbackName m_callBack;
}

void Foo::someFunc()
{
    m_callBack(1);
}

我曾经在 main() 中调用它,或者只是引用类似签名的函数..

void someOtherFunction(int x)
{
    cout << x;
}

int main()
{
    Foo::someCallbackName callBack = someOtherFunction;
    Foo foo(5, callBack);
}

不过我决定,我可能需要 someOtherFunction 作为 class 成员,并将其作为 class 的一部分。但是,使用 class 成员函数 someOtherFunction 作为回调需要使其成为静态的,这工作正常,但这意味着它无法访问非静态的 class 成员,这排序打败了把它放在 class.

中的目的

我尝试使用: C++ callback using class member

和中给出的结构访问: https://en.cppreference.com/w/cpp/utility/functional/bind

..但是好像不行,把std::bind改成

Foo::someCallbackName callBack = std::bind(not_sure_what_to_use_here);

一直报错说没有合适的转换,这让我觉得代码中使用 std::bind 的回调签名或机制是错误的。

保持classFoo不变,m_callBack如何调用someOtherFunction

您可以 "bind" 使用 labmda 回调特定对象的非静态成员函数:

class X {
  public:
    void someOtherFunction(int x) const { std::cout << x; }
};

int main() 
  X x;
  Foo::someCallbackName callBack = [&x](int i){ x.someOtherFunction(i); };
  Foo foo(5, callBack);
  foo.someFunc();
}

现场演示:https://wandbox.org/permlink/fUmrnD6xn1xr7zn0


为了避免在 x 被销毁后出现悬挂引用,您可以使用 共享指针 ,如下所示(注意它是通过值 [= 捕获 26=]):

Foo::someCallbackName callBack;
{
  auto ptr_x = std::make_shared<X>();
  callBack = [ptr_x](int i){ ptr_x->someOtherFunction(i); };
}
Foo foo(5, callBack);
foo.someFunc();

现场演示:https://wandbox.org/permlink/23euPcuDUsDENdRe

正如@Daniel Langr 所说,您可以使用 lambda 函数。

否则,如果您想使用作为成员函数的回调,您需要将其绑定到一个对象。

#include <functional>
#include <iostream>

class Foo
{
public:
    using someCallbackName = std::function<void(int)>;
    void someFunc();
    Foo(int, someCallbackName);

private:
    someCallbackName m_callBack;
};

class Bar
{
public:
    void someOtherFunction(int x);
};

Foo::Foo(int i, someCallbackName cb)
{
    m_callBack = cb;
    someFunc();
}

void Foo::someFunc()
{
    m_callBack(1);
}

void Bar::someOtherFunction(int x)
{
    std::cout << x;
}

int main()
{
    Bar bar;
    Foo::someCallbackName callBack = std::bind(&Bar::someOtherFunction, &bar, std::placeholders::_1);
    Foo foo(5, callBack);
}

执行此操作时请注意 bar 的生命周期。

解决生命周期问题的一种方法是让 Foo 负责 Bar 的生命周期(这种设计模式称为组合)。

#include <functional>
#include <iostream>

// If you declare both class in different files you may need to look into "forward declaration"
class Bar
{
public:
    void someOtherFunction(int x);
};

class Foo
{
public:
    using someCallbackName = std::function<void(int)>;
    void someFunc();
    Foo(int, someCallbackName);

private:
    someCallbackName m_callBack;
    Bar bar;
};

Foo::Foo(int i)
{
    m_callBack = std::bind(&Bar::someOtherFunction, &bar, std::placeholders::_1);;
    someFunc();
}

// someOtherFunction and someFunc are left unchanged

int main()
{
    Foo foo(5);
}