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

如何通过模板化实现Wrapper类高效转发Worker类成员函数调用

问题:批量实现Wrapper对Worker同名方法的参数转发

现有代码结构如下:

class Wrapper {
public:
  AnyType Foo(std::uint64_t unique_id, Args&&... args) {
     return worker_map[unique_id]->Foo(std::forward<Args>(args)...);
  }
  AnotherType Bar(std::uint64_t unique_id, Args&&... args) {
     return worker_map[unique_id]->Bar(std::forward<Args>(args)...);
  }
private:
  std::unordered_map<std::uint64_t, std::unique_ptr<Worker>> worker_map;
};

class Worker {
public:
 AnyType Foo(<some arguments>);
 AnotherType Bar(<another arguments>);
 // 更多成员函数
};

Wrapper的所有公有成员函数逻辑一致:通过unique_id从worker_map中匹配对应的Worker实例,再把剩余参数转发给Worker中同名的成员函数。但Worker已有大量成员函数,且后续会持续增删改,希望通过模板化方法名的方式减少重复代码。


可行解决方案

方案1:模板成员函数+成员函数指针

定义一个通用的模板转发函数,接收Worker的成员函数指针作为参数,统一处理实例查找和参数转发:

#include <functional>
#include <memory>
#include <unordered_map>
#include <stdexcept>

class Worker {
public:
    int Foo(int a, double b) { return static_cast<int>(a + b); }
    std::string Bar(const std::string& s) { return "Hello, " + s; }
    // 其他成员函数...
};

class Wrapper {
public:
    // 转发非const成员函数
    template<typename Ret, typename... Args, typename... CallArgs>
    Ret invoke(std::uint64_t unique_id, Ret (Worker::*func)(Args...), CallArgs&&... args) {
        auto it = worker_map.find(unique_id);
        if (it == worker_map.end()) {
            throw std::invalid_argument("Invalid unique_id");
        }
        return (it->second.get()->*func)(std::forward<CallArgs>(args)...);
    }

    // 转发const成员函数(如果需要)
    template<typename Ret, typename... Args, typename... CallArgs>
    Ret invoke(std::uint64_t unique_id, Ret (Worker::*func)(Args...) const, CallArgs&&... args) const {
        auto it = worker_map.find(unique_id);
        if (it == worker_map.end()) {
            throw std::invalid_argument("Invalid unique_id");
        }
        return (it->second.get()->*func)(std::forward<CallArgs>(args)...);
    }

private:
    std::unordered_map<std::uint64_t, std::unique_ptr<Worker>> worker_map;
};

使用示例:

Wrapper w;
// 假设已向worker_map添加id为1的Worker实例
w.invoke(1, &Worker::Foo, 5, 3.14);
w.invoke(1, &Worker::Bar, "World");

这种方式无需为每个Worker方法单独编写Wrapper成员函数,新增Worker方法时直接通过invoke调用即可,完全不需要修改Wrapper代码。

方案2:C++20 模板化方法名(更直观的调用方式)

如果项目使用C++20,可以利用auto模板参数和std::invoke实现更简洁的调用:

#include <functional>
#include <memory>
#include <unordered_map>
#include <stdexcept>
#include <utility>

class Worker {
public:
    int Foo(int a, double b) { return static_cast<int>(a + b); }
    std::string Bar(const std::string& s) { return "Hello, " + s; }
    // 其他成员函数...
};

class Wrapper {
public:
    template<auto Func, typename... Args>
    auto call(std::uint64_t unique_id, Args&&... args) {
        auto it = worker_map.find(unique_id);
        if (it == worker_map.end()) {
            throw std::invalid_argument("Invalid unique_id");
        }
        return std::invoke(Func, *it->second, std::forward<Args>(args)...);
    }

    // const版本
    template<auto Func, typename... Args>
    auto call(std::uint64_t unique_id, Args&&... args) const {
        auto it = worker_map.find(unique_id);
        if (it == worker_map.end()) {
            throw std::invalid_argument("Invalid unique_id");
        }
        return std::invoke(Func, *it->second, std::forward<Args>(args)...);
    }

private:
    std::unordered_map<std::uint64_t, std::unique_ptr<Worker>> worker_map;
};

使用示例:

Wrapper w;
w.call<&Worker::Foo>(1, 5, 3.14);
w.call<&Worker::Bar>(1, "World");

这种方式调用时更直观,模板参数直接指定Worker的成员函数,返回值由编译器自动推导,代码更简洁。


关键注意事项

  • 必须处理unique_id不存在的情况,避免空指针访问导致崩溃
  • 使用std::forward保证参数的完美转发,保留参数的左值/右值属性
  • 如果Worker包含const成员函数,需要单独实现const版本的转发函数

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 10:42:21