调用带可变参数的模板类成员函数时遇编译错误求助
成员函数作为参数传入模板函数的编译错误解决方法
嘿,我来帮你搞定这个问题!你遇到的错误本质是成员函数指针的调用方式不符合C++语法规则,咱们一步步拆解原因和解决方案:
问题原因分析
你在TestRoutine里调用eq.Call(this,&Example::Parse);时,模板推导出来的类型是:
F = Example*(也就是你传入的this)Args = {void (Example::*)()}(也就是成员函数指针&Example::Parse)
然后在EventQueue::Call里执行func(args...),相当于尝试用Example*类型的func去调用成员函数指针,这完全不对——C++里成员函数必须通过对象(或对象指针)来调用,正确的语法应该是(obj->*mem_func)(),而不是直接用对象指针当函数调用。
三种可行的解决方案
方案1:使用Lambda表达式(最简洁推荐)
用lambda把成员函数的调用逻辑包装起来,lambda可以捕获this,内部直接调用成员函数,这样Call接收的是一个可调用的lambda对象,直接执行就没问题:
void TestRoutine(){ eq.Call([this](){ this->Parse(); }); }
这种方式代码直观,不需要额外的头文件,是C++11及以后最常用的处理方式。
方案2:使用std::bind绑定对象与成员函数
需要包含<functional>头文件,用std::bind把this和成员函数指针绑定成一个可调用的仿函数:
#include <functional> // ... void TestRoutine(){ eq.Call(std::bind(&Example::Parse, this)); }
std::bind会返回一个可以直接调用的对象,Call执行它的时候,会自动用绑定好的this去调用Parse函数。
方案3:修改EventQueue::Call模板,原生支持成员函数
如果你想让EventQueue的Call方法直接支持成员函数调用,可以新增一个专门处理成员函数的模板重载:
class EventQueue { public: EventQueue(int size) {} void Dispatch() {} // 处理普通函数、lambda、仿函数等可调用对象 template <typename F, typename... Args> void Call(F func, Args... args) { func(args...); } // 专门处理成员函数的重载版本 template <typename T, typename MemFunc, typename... Args> void Call(T* obj, MemFunc mem_func, Args... args) { (obj->*mem_func)(args...); } void DispatchForever() {} };
这样你原来的eq.Call(this,&Example::Parse);就能直接编译通过了,模板会自动匹配到成员函数的重载版本。
相关学习资源推荐
- 《C++ Primer(第5版)》:里面有详细的模板编程、成员函数指针、lambda表达式和
std::bind的讲解,非常适合系统掌握这些知识点。 - 《Effective C++》《More Effective C++》:书中的条款会帮你避开C++里像成员函数指针、可调用对象这类常见的陷阱,理解背后的设计逻辑。
- cppreference文档:可以查阅关于lambda表达式、
std::bind、成员函数指针的语法细节和示例,是C++开发者必备的参考资料。
内容的提问来源于stack exchange,提问作者Tordur
相关产品推荐
相关产品推荐

