在map中存储函数指针报错,求错误原因及修复方案
问题:类成员map存储成员函数指针时触发E0289错误
尝试在类的map成员中存储成员函数指针,编译时出现E0289错误,但如果把相关逻辑放到main函数里就能正常运行,需要解释错误原因并提供修复方案。
原代码
#include <boost/variant.hpp> #include <map> #include <iostream> #include <map> using namespace boost; class obj { public: int num1; int num2; std::string s1; std::string s2; }; typedef boost::variant<int, float, double, std::string> MultiType; typedef MultiType(*FnPtr)(obj); class c { public: MultiType add(obj o); std::map<std::string, FnPtr> metricToFuncMap = { { "i", add } }; }; MultiType c::add(obj o) { { MultiType x; x = o.num1 + o.num2; return x; } } int main() { obj o; //add MultiType d; d = 1; o.num1 = 1; o.num2 = 2; //concat o.s1 = "hello"; o.s2 = "world"; c c; MultiType x = c.metricToFuncMap["i"](o); std::cout << get<int>(x); return 0; }
错误信息
E0289 no instance of constructor "std::map<_Kty, _Ty, _Pr, _Alloc>::map [with _Kty=std::string, _Ty=FnPtr, _Pr=std::less<std::string>, _Alloc=std::allocator<std::pair<const std::string, FnPtr>>]" matches the argument list
错误原因
核心问题是类的非静态成员函数和普通函数指针不兼容:
- 你定义的
FnPtr是普通函数指针类型,指向的函数无需依赖对象实例就能调用。 - 但
c::add是类的非静态成员函数,这类函数会隐式携带一个this指针参数,用来指向调用它的对象实例,实际类型是MultiType (c::*)(obj),和FnPtr完全不匹配,因此无法存入map。 - 若把逻辑放到main里用普通非成员函数,类型匹配就不会报错。
修复方案
方案1:将成员函数改为静态函数
如果add不需要访问类的非静态成员变量,改成静态成员函数即可——静态函数没有隐式this指针,类型和FnPtr匹配:
#include <boost/variant.hpp> #include <map> #include <iostream> #include <map> using namespace boost; class obj { public: int num1; int num2; std::string s1; std::string s2; }; typedef boost::variant<int, float, double, std::string> MultiType; typedef MultiType(*FnPtr)(obj); class c { public: static MultiType add(obj o); // 改为静态函数 std::map<std::string, FnPtr> metricToFuncMap = { { "i", add } }; }; MultiType c::add(obj o) { MultiType x; x = o.num1 + o.num2; return x; } int main() { obj o; o.num1 = 1; o.num2 = 2; c c; MultiType x = c.metricToFuncMap["i"](o); std::cout << get<int>(x); return 0; }
方案2:使用成员函数指针类型存储
必须保留非静态成员函数时,把map的value类型改成成员函数指针,调用时结合对象实例:
#include <boost/variant.hpp> #include <map> #include <iostream> #include <map> using namespace boost; class obj { public: int num1; int num2; std::string s1; std::string s2; }; typedef boost::variant<int, float, double, std::string> MultiType; // 定义类c的成员函数指针类型 typedef MultiType (c::*MemFnPtr)(obj); class c { public: MultiType add(obj o); std::map<std::string, MemFnPtr> metricToFuncMap = { { "i", &c::add } }; // 取成员函数地址 }; MultiType c::add(obj o) { MultiType x; x = o.num1 + o.num2; return x; } int main() { obj o; o.num1 = 1; o.num2 = 2; c c; // 调用成员函数指针需要绑定对象实例 MultiType x = (c.*c.metricToFuncMap["i"])(o); std::cout << get<int>(x); return 0; }
方案3:使用std::function封装(更灵活)
需要兼容lambda、绑定参数等场景时,用std::function封装:
#include <boost/variant.hpp> #include <map> #include <iostream> #include <functional> // 引入std::function头文件 using namespace boost; class obj { public: int num1; int num2; std::string s1; std::string s2; }; typedef boost::variant<int, float, double, std::string> MultiType; class c { public: MultiType add(obj o); // 用lambda绑定当前对象的this,封装成std::function std::map<std::string, std::function<MultiType(obj)>> metricToFuncMap = { {"i", [this](obj o) { return this->add(o); }} }; }; MultiType c::add(obj o) { MultiType x; x = o.num1 + o.num2; return x; } int main() { obj o; o.num1 = 1; o.num2 = 2; c c; MultiType x = c.metricToFuncMap["i"](o); std::cout << get<int>(x); return 0; }
内容的提问来源于stack exchange,提问作者Anees
相关产品推荐
相关产品推荐

