如何用C++17标准库实现对象间方法的事件绑定及参数自动推导?
C++17实现无占位符的事件-处理器绑定
需求场景
想要实现将一个对象的事件成员方法,绑定到另一个对象的处理成员方法上,期望调用形式简洁直接,比如:
connect(&a, &A::eventA, &b, &B::handlerA);
无需根据事件/处理器的参数数量手动调整绑定代码。
用std::bind的局限
直接用std::bind实现的话,必须显式指定std::placeholders::_1、_2等占位符,不同参数个数的成员函数需要写不同的绑定逻辑,扩展性很差。比如绑定一个单参数方法要写:
std::bind(&B::handlerA, &b, std::placeholders::_1);
如果是双参数方法又要改成std::placeholders::_1, std::placeholders::_2,非常繁琐。
C++17解决方案:带自动推导的lambda实现通用connect
利用C++17的模板参数自动推导特性,结合lambda表达式的完美转发,可以实现一个无需占位符的通用connect函数,自动适配任意参数数量的成员函数:
#include <functional> #include <iostream> // 通用connect模板函数 template<typename EventObj, typename EventFunc, typename HandlerObj, typename HandlerFunc> auto connect(EventObj* event_obj, EventFunc event_func, HandlerObj* handler_obj, HandlerFunc handler_func) { return [event_obj, event_func, handler_obj, handler_func](auto&&... args) { // 先调用事件方法,再将参数转发给处理方法 (event_obj->*event_func)(std::forward<decltype(args)>(args)...); (handler_obj->*handler_func)(std::forward<decltype(args)>(args)...); }; } // 示例类A(事件触发方) class A { public: void eventA(int x) { std::cout << "Event A triggered with value: " << x << "\n"; } void eventB(std::string msg, double val) { std::cout << "Event B triggered: " << msg << ", " << val << "\n"; } }; // 示例类B(事件处理方) class B { public: void handlerA(int x) { std::cout << "Handler A processed value: " << x * 2 << "\n"; } void handlerB(std::string msg, double val) { std::cout << "Handler B processed: " << msg << " -> " << val + 1.5 << "\n"; } }; int main() { A a; B b; // 绑定单参数事件与处理器 auto bound_eventA = connect(&a, &A::eventA, &b, &B::handlerA); bound_eventA(10); // 绑定双参数事件与处理器 auto bound_eventB = connect(&a, &A::eventB, &b, &B::handlerB); bound_eventB("Test", 3.2); return 0; }
代码说明
- 模板函数
connect自动推导事件对象、事件方法、处理对象、处理方法的类型,无需手动指定模板参数。 - 返回的lambda表达式使用
auto&&... args实现可变参数的完美转发,适配任意参数数量的成员函数。 - 调用绑定后的函数时,会先触发事件方法,再将参数转发给处理方法,你可以根据需求调整执行顺序或逻辑。
内容的提问来源于stack exchange,提问作者Maxim
相关产品推荐
相关产品推荐

