You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现可存储多种类型C++函数的FunctionPackage类?

实现支持存储任意类型函数的FunctionPackage

要解决不同签名函数的存储问题,核心思路是用类型擦除来统一存储任意类型的函数对象。C++17及以上可以直接用std::any实现,无需依赖宏,下面是具体方案:

修改后的FunctionPackage类

#include <unordered_map>
#include <string>
#include <any>
#include <functional>
#include <stdexcept>

class FunctionPackage {
public:
    // 模板注册函数,支持任意类型的函数/函数对象
    template<typename T>
    void register_id(std::string name, T function) {
        functions[name] = function;
    }

    // 模板获取函数,需指定目标函数的签名类型
    template<typename FuncType>
    FuncType get(const std::string& name) const {
        auto it = functions.find(name);
        if (it == functions.end()) {
            throw std::runtime_error("Function not found: " + name);
        }
        try {
            return std::any_cast<FuncType>(it->second);
        } catch (const std::bad_any_cast& e) {
            throw std::runtime_error("Function type mismatch for: " + name + ", error: " + e.what());
        }
    }

private:
    // 用std::any擦除类型,存储任意可拷贝的函数对象
    std::unordered_map<std::string, std::any> functions;
};

使用示例

#include <iostream>

// 不同签名的测试函数
void func_void() {
    std::cout << "This is a void() function\n";
}

int func_int(int x) {
    return x * 2;
}

std::string func_string(const std::string& s) {
    return "Hello, " + s;
}

int main() {
    FunctionPackage pkg;

    // 注册各种类型的函数(包括lambda)
    pkg.register_id("void_func", func_void);
    pkg.register_id("int_func", func_int);
    pkg.register_id("string_func", func_string);
    pkg.register_id("lambda", []() { std::cout << "Lambda function\n"; });

    // 获取并调用函数,需明确指定签名类型
    auto void_func = pkg.get<std::function<void()>>("void_func");
    void_func();

    auto int_func = pkg.get<std::function<int(int)>>("int_func");
    std::cout << "int_func(5) = " << int_func(5) << "\n";

    auto string_func = pkg.get<std::function<std::string(const std::string&)>>("string_func");
    std::cout << string_func("World") << "\n";

    auto lambda = pkg.get<std::function<void()>>("lambda");
    lambda();

    return 0;
}

关键说明

  • 类型擦除原理:std::any可以存储任意可拷贝构造的对象,通过擦除具体类型,让不同签名的函数能存入同一个容器。
  • 类型安全保障:获取函数时必须指定准确的签名类型(用std::function<签名>),类型不匹配或函数不存在时会抛出异常,避免运行时错误。
  • C++17之前的替代方案:如果无法使用C++17,可以手动实现类型擦除基类——定义一个空基类FunctionWrapper,再为每个函数签名实现派生类,不过std::any的写法更简洁高效。

内容的提问来源于stack exchange,提问作者degawong

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 12:42:28