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

如何在C++中设计可容纳任意类型函数的容器以实现服务器函数注册?

实现支持任意函数注册的服务器

当然可以用unordered_map<string, ...>的方式存储不同签名的函数,核心是通过类型擦除把各种函数统一为可存储的同一类型。以下是两种基于标准库的实现方案:

方案1:基于多态的类型擦除

通过抽象基类定义统一接口,模板派生类存储具体函数,利用多态实现类型擦除:

#include <unordered_map>
#include <memory>
#include <functional>
#include <iostream>
#include <string>

// 抽象函数包装类,提供统一的销毁接口
class FunctionWrapper {
public:
    virtual ~FunctionWrapper() = default;
};

// 模板子类,存储具体签名的函数
template<typename Func>
class ConcreteFunction : public FunctionWrapper {
public:
    explicit ConcreteFunction(Func func) : func_(std::move(func)) {}

    // 调用具体函数的模板方法
    template<typename... Args>
    void invoke(Args&&... args) {
        func_(std::forward<Args>(args)...);
    }

private:
    Func func_;
};

class Server {
public:
    // 注册任意签名的函数
    template<typename Func>
    void register_func(const std::string& name, Func func) {
        functions_[name] = std::make_unique<ConcreteFunction<Func>>(std::move(func));
    }

    // 调用指定函数,参数需与注册的签名匹配
    template<typename... Args>
    void Call(const std::string& name, Args&&... args) {
        auto it = functions_.find(name);
        if (it == functions_.end()) {
            std::cerr << "函数 " << name << " 未找到\n";
            return;
        }

        // 向下转型到具体函数类型,参数不匹配时会返回nullptr
        auto* concrete_func = dynamic_cast<ConcreteFunction<std::function<void(Args...)>>*>(it->second.get());
        if (!concrete_func) {
            std::cerr << "函数 " << name << " 的签名与调用参数不匹配\n";
            return;
        }

        concrete_func->invoke(std::forward<Args>(args)...);
    }

private:
    std::unordered_map<std::string, std::unique_ptr<FunctionWrapper>> functions_;
};

// 测试代码
int main() {
    Server server;

    server.register_func("Add", [](int a, int b){ std::cout << a + b << "\n"; });
    server.register_func("Echo", [](const std::string& str){ std::cout << str << "\n"; });

    server.Call("Add", 12, 13);       // 输出:25
    server.Call("Echo", "Hello World");// 输出:Hello World

    // 错误示例:参数类型不匹配会触发运行时提示
    // server.Call("Add", "12", "13");
    return 0;
}

说明

  • 兼容C++11及以上版本,利用多态实现类型擦除;
  • 调用时需保证参数类型与注册函数的签名完全匹配,否则dynamic_cast会失败并返回空指针;
  • 内存通过unique_ptr自动管理,避免内存泄漏。

方案2:基于std::any的类型擦除

C++17引入的std::any可以直接存储任意类型的std::function,代码更简洁:

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

class Server {
public:
    // 注册任意签名的函数,自动转为对应的std::function
    template<typename Func>
    void register_func(const std::string& name, Func func) {
        functions_[name] = std::function(std::move(func));
    }

    // 调用指定函数,参数不匹配时会抛出异常
    template<typename... Args>
    void Call(const std::string& name, Args&&... args) {
        auto it = functions_.find(name);
        if (it == functions_.end()) {
            std::cerr << "函数 " << name << " 未找到\n";
            return;
        }

        try {
            // 尝试将std::any转换为对应签名的std::function
            auto& target_func = std::any_cast<std::function<void(Args...)>>(it->second);
            target_func(std::forward<Args>(args)...);
        } catch (const std::bad_any_cast& e) {
            std::cerr << "函数签名不匹配:" << e.what() << "\n";
        }
    }

private:
    std::unordered_map<std::string, std::any> functions_;
};

// 测试代码
int main() {
    Server server;

    server.register_func("Add", [](int a, int b){ std::cout << a + b << "\n"; });
    server.register_func("Echo", [](const std::string& str){ std::cout << str << "\n"; });

    server.Call("Add", 12, 13);       // 输出:25
    server.Call("Echo", "Hello World");// 输出:Hello World

    // 错误示例:参数类型不匹配会触发异常
    // server.Call("Add", "12", "13");
    return 0;
}

说明

  • 依赖C++17及以上版本,代码结构更紧凑;
  • 参数不匹配时会抛出std::bad_any_cast异常,需要捕获处理;
  • 无需手动管理多态类内存,std::any会自动处理存储对象的生命周期。

总结

两种方案都能实现“注册任意函数+按名调用”的需求,核心都是通过类型擦除把不同签名的函数统一存储到unordered_map中。如果需要兼容旧版本C++,选方案1;如果使用C++17及以上,方案2更简洁易用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 12:32:05