自定义JIT语言Trunk中存储任意函数指针至std::map的类型问题
问题分析与解决方案
编译错误拆解
你的代码存在两个核心问题:
- 函数调用运算符语法错误:
Ret operator(Args... args)不符合C++语法规范,函数调用运算符必须写成operator()。 - 模板类型无法统一存储:
trunk::Function是模板类,不同模板实例(如Function<void, std::string>和Function<int, int>)是完全不同的类型,无法直接放入同一个std::map中。
完整修正代码
#include <iostream> #include <map> #include <memory> #include <string> #include <utility> namespace trunk { // 非模板基类,用于实现类型擦除 class BaseFunction { public: virtual ~BaseFunction() = default; }; template<typename Ret, typename... Args> class Function : public BaseFunction { using FunctionType = Ret (*)(Args...); public: explicit Function(FunctionType callable) : _callable(callable) {} // 修复函数调用运算符的语法错误 Ret operator()(Args... args) { return _callable(std::forward<Args>(args)...); } private: FunctionType _callable; }; namespace globals { void print(std::string s) { std::cout << s << std::endl; } } } // 全局函数映射表:使用智能指针存储基类对象,实现任意函数的统一存储 static std::map<std::string, std::unique_ptr<trunk::BaseFunction>> function_map; int main() { // 向映射表添加print函数 function_map.emplace( "print", std::make_unique<trunk::Function<void, std::string>>(&trunk::globals::print) ); // 调用示例:需向下转型到具体Function类型才能调用 if (auto it = function_map.find("print"); it != function_map.end()) { auto* print_func = dynamic_cast<trunk::Function<void, std::string>*>(it->second.get()); if (print_func) { (*print_func)("Hello, Trunk!"); } } return 0; }
关键修复说明
修复运算符语法
将Ret operator(Args... args)修改为Ret operator()(Args... args),这是C++中重载函数调用运算符的标准写法,原代码缺少括号导致编译器无法识别。实现类型擦除
- 定义非模板抽象基类
BaseFunction,作为所有Function模板实例的公共父类; - 将
std::map的value类型改为std::unique_ptr<BaseFunction>,利用多态特性存储任意签名的Function实例,解决不同模板类型无法共存的问题。
- 定义非模板抽象基类
内存管理优化
使用std::unique_ptr管理基类对象内存,避免手动内存泄漏,符合现代C++内存管理规范。函数调用逻辑
调用存储的函数时,需要通过dynamic_cast将基类指针转换为具体的Function类型——这在JIT场景中是合理的,因为你必须明确函数的签名才能正确传递参数并处理返回值。
内容的提问来源于stack exchange,提问作者TheEagle
相关产品推荐
相关产品推荐

