C++如何将类成员函数作为参数传递给全局函数?
问题原因分析
1. 模板参数声明错误
你当前定义的模板签名为template <typename R, typename A, typename C> void printAtEnd(R (C::*func)(A)),当你传入无参成员函数&Student::show时,将A指定为void会触发语法错误:C++ 不允许将void作为普通形参的类型,只有函数参数列表直接写void才代表无参,无法通过类型参数替换为void实现无参函数的声明。
2. 成员函数调用缺少实例
成员函数指针不能直接调用,必须绑定到对应类的实例上才能执行,你当前代码中直接写func()完全不符合成员函数的调用规则,就算解决了模板参数的问题也会触发编译错误。
修复方案
这里提供两种常用的修复方案,可根据你的项目C++版本选择:
方案1:适配无参成员函数的模板修改(兼容C++98)
直接调整模板明确接收无参成员函数,同时增加类实例入参:
// 修改后的printAtEnd模板 template <typename C> void printAtEnd(C& instance, void (C::*func)()){ int i; cout << "请选择以下操作之一\n"; cout << "\t1. 返回主菜单\n"; cout << "\t2. 重试当前操作\n"; cout << "\t3. 退出程序\n"; cin >> i; switch(i){ case 1: mainMenu(); break; case 2: (instance.*func)(); break; // 绑定实例调用成员函数 case 3: exit(0); break; } }
在Student::show中调用时传入当前实例即可:
printAtEnd<Student>(*this, &Student::show);
方案2:lambda+可调用对象模板(C++11及以上,更灵活)
如果你的项目支持C++11及以上标准,用lambda包裹重试逻辑是最省心的方案,不需要处理复杂的成员函数指针规则:
// 修改后的printAtEnd模板,支持任意无参可调用对象 template <typename Func> void printAtEnd(Func retry_func){ int i; cout << "请选择以下操作之一\n"; cout << "\t1. 返回主菜单\n"; cout << "\t2. 重试当前操作\n"; cout << "\t3. 退出程序\n"; cin >> i; switch(i){ case 1: mainMenu(); break; case 2: retry_func(); break; case 3: exit(0); break; } }
调用时直接传入捕获当前实例的lambda即可:
printAtEnd([this](){ show(); });
这种方案扩展性更强,后续如果需要重试任意自定义逻辑,都可以直接用lambda包裹传入,不需要修改模板代码。
内容的提问来源于stack exchange,提问作者Aesha Amoli
相关产品推荐
相关产品推荐

