如何在C++中为支持不同参数的成员函数指针编写typedef?
问题描述
现有一套基于用户输入执行类成员函数的实现,核心定义如下:
typedef int(A::*FUNCPTR)(); std::map<const std::string, FUNCPTR> func_map;
初始化代码:
func_map["sum"] = &A::cmd_sum; func_map["print"] = &A::cmd_print;
类A中的函数声明:
int cmd_sum(); int cmd_print();
程序会根据用户输入调用对应函数,两个函数均返回int类型。
现在需要扩展功能:让cmd_sum接收两个int参数,cmd_print保持无参(用于打印Hello world),要兼容以下函数声明:
int cmd_sum(int a, int b); int cmd_print();
解决方案
不同参数的成员函数指针类型不兼容,没法直接存入同一个std::map,必须用统一的可调用包装类型来适配,这里推荐两种实现方式:
方式一:用std::function统一包装(兼容所有C++版本)
这是最通用的方案,通过lambda把不同参数的成员函数转换成统一的包装类型。
1. 修改类型定义和map
引入<functional>和<vector>头文件,替换原有的指针定义:
#include <functional> #include <vector> // 统一包装类型:接收A的实例引用、参数列表,返回int using FuncWrapper = std::function<int(A&, const std::vector<int>&)>; std::map<const std::string, FuncWrapper> func_map;
2. 重新初始化map
用lambda把两个函数适配成FuncWrapper类型,同时处理参数校验:
// 适配带两个参数的cmd_sum func_map["sum"] = [](A& obj, const std::vector<int>& args) -> int { if (args.size() != 2) { // 参数数量不对时返回错误码,可根据需求调整 return -1; } return obj.cmd_sum(args[0], args[1]); }; // 适配无参的cmd_print,直接忽略参数列表 func_map["print"] = [](A& obj, const std::vector<int>&) -> int { return obj.cmd_print(); };
3. 修改调用逻辑
解析用户输入的命令和参数(把输入的数字转成std::vector<int>),然后调用包装后的函数:
// 示例调用逻辑 A obj; std::string input_cmd = "sum"; std::vector<int> input_args = {3, 5}; auto cmd_iter = func_map.find(input_cmd); if (cmd_iter != func_map.end()) { int result = cmd_iter->second(obj, input_args); // 这里可以处理返回结果,比如打印或判断执行状态 } else { // 处理未知命令的情况 }
方式二:用std::variant存储不同指针(C++17及以上)
如果项目用的是C++17或更高版本,可以用std::variant直接存储不同类型的成员函数指针,调用时通过类型判断执行:
1. 修改类型定义和map
引入<variant>头文件,定义两种成员函数指针类型,用variant作为map的值:
#include <variant> // 定义两种成员函数指针类型 using FuncNoParam = int(A::*)(); using FuncTwoParams = int(A::*)(int, int); std::map<const std::string, std::variant<FuncNoParam, FuncTwoParams>> func_map;
2. 初始化map
直接存入不同类型的成员函数指针:
func_map["sum"] = &A::cmd_sum; func_map["print"] = &A::cmd_print;
3. 修改调用逻辑
用std::visit遍历variant,通过constexpr判断类型后调用:
// 示例调用逻辑 A obj; std::string input_cmd = "print"; std::vector<int> input_args = {}; auto cmd_iter = func_map.find(input_cmd); if (cmd_iter != func_map.end()) { std::visit([&](auto&& func) { using FuncType = std::decay_t<decltype(func)>; if constexpr (std::is_same_v<FuncType, FuncNoParam>) { obj.*func(); } else if constexpr (std::is_same_v<FuncType, FuncTwoParams>) { if (input_args.size() == 2) { obj.*func(input_args[0], input_args[1]); } } }, cmd_iter->second); }
内容的提问来源于stack exchange,提问作者rere
相关产品推荐
相关产品推荐

