如何实现BIND_THIS宏以简化成员函数与this指针的绑定(基于std::bind_front)
如何实现BIND_THIS宏以简化成员函数与this指针的绑定(基于std::bind_front)
我完全懂你这种痛点——在写满异步回调的代码里,反复敲&MySuperLongClassName::MyEvenLongerFunction真的太折磨人了,尤其是对比同步调用时直接写SomeFunction(1,2)的爽感。你想要的BIND_THIS宏完全可以实现,只需要修正你原来的宏里的类型问题就行。
核心解决方案:修正类型引用问题
你之前的宏差一步就成功了,问题出在decltype(*this)返回的是类的引用类型(T&),而成员函数指针需要的是原始类类型T。我们可以用C++17引入的std::remove_reference_t来剥离引用,得到正确的类类型。
最终的宏定义如下:
#include <functional> #include <type_traits> #define BIND_THIS(_fn) std::bind_front(&std::remove_reference_t<decltype(*this)>::_fn, this)
验证你的示例代码
把这个宏用到你的类里,完全符合你想要的简洁写法:
class MyObnoxiousLongClassName { public: void SomeFunction(int a, int b) { // 成员函数实现 } auto MakeSomeCallback() { return BIND_THIS(SomeFunction); } }; class MyOtherSimilarlyNamedClass { public: void AnOtherFunction(float y) { // 成员函数实现 } auto DoSomethingElse() { return BIND_THIS(AnOtherFunction); } };
这个宏展开后的代码和你手动写的std::bind_front(&MyObnoxiousLongClassName::SomeFunction, this)完全等价,而且简洁度拉满,和同步调用的写法一样清爽。
为什么这个宏能工作?
decltype(*this)获取的是当前对象的类型,结果是T&(因为*this返回的是对象的左值引用)std::remove_reference_t<decltype(*this)>会把引用类型剥离,得到原始的类类型T- 这样
&T::_fn就能正确获取到成员函数的指针,再配合this传给std::bind_front,就完成了和手动绑定完全一致的逻辑
可选:无宏的C++20替代方案
如果你对宏有所顾虑(比如宏的参数展开坑、调试时的可读性问题),C++20的lambda可以实现同样的简洁效果,而且类型更安全:
auto MakeSomeCallback() { return [this](auto&&... args) noexcept(noexcept(SomeFunction(std::forward<decltype(args)>(args)...))) { return SomeFunction(std::forward<decltype(args)>(args)...); }; }
这个lambda会完美转发所有参数,还保留了原函数的noexcept属性,类型推导也更友好。不过如果你就是想要最接近BIND_THIS(SomeFunction)的写法,宏方案还是最直接的。
兼容性说明
你用的GCC 13.3.0完全支持std::remove_reference_t(C17特性)和std::bind_front(C20特性),所以这个方案没有兼容性问题。
内容来源于stack exchange
相关产品推荐
相关产品推荐

