使用 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();
正如@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);
}
这可能之前已经探索过,但我不确定它是如何工作的,以及在我的特定情况下应该如何..
基本上我有一个 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();
正如@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);
}