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

能否从基类函数参数推导模板参数?优化回调包装器写法

如何从基类虚函数自动推导Callback模板的参数?

完全可以实现!咱们核心思路就是用模板元编程自动提取基类里onFinish虚函数的参数类型,再也不用手动写那些冗长的模板参数了。

先回顾下你现有的代码:

#include <optional>
#include <vector>
#include <tuple>
#include <future>

// 你的回调基类
class CallbackFilterProducts { 
public: 
    virtual ~CallbackFilterProducts() {} 
    virtual void onFinish(const std::optional<class Page>& page, const std::vector<class Product>& products) = 0; 
}; 

// 原Callback模板(需要手动指定参数)
template <typename T, typename... Args> 
struct Callback : T { 
    Callback() {} 
    void onFinish(Args&&... args) override { 
        _promise.set_value(std::make_tuple(std::forward<Args>(args)...)); 
    } 
    auto&& promise() { return _promise; } 
private: 
    std::promise<std::tuple<std::remove_const_t<std::remove_reference_t<Args>>...>> _promise; 
};

之前你必须这么写,参数列表特别长:

auto callback = std::make_shared<Callback<CallbackFilterProducts, const std::optional<Page>&, const std::vector<Product>&>>();

接下来咱们一步步改造,实现你想要的简化写法:

第一步:用模板特化自动提取函数参数

我们可以写一个带偏特化的辅助模板,专门解析类中onFinish函数的签名:

// 辅助模板:用来提取成员函数的参数、返回值等信息
template<typename Func>
struct FuncTraits;

// 偏特化:匹配返回值为void、参数为Args...的非const成员函数
template<typename Class, typename... Args>
struct FuncTraits<void(Class::*)(Args...)> {
    using PromiseType = std::promise<std::tuple<std::remove_const_t<std::remove_reference_t<Args>>...>>;
    // 把原函数的参数类型暴露出来
    using FuncSignature = void(Class::*)(Args...);
};

// 额外特化:处理const版本的onFinish函数(如果需要的话)
template<typename Class, typename... Args>
struct FuncTraits<void(Class::*)(Args...) const> {
    using PromiseType = std::promise<std::tuple<std::remove_const_t<std::remove_reference_t<Args>>...>>;
    using FuncSignature = void(Class::*)(Args...) const;
};

// 主模板:自动匹配基类的onFinish函数
template<typename T, typename Func = decltype(&T::onFinish)>
struct CallbackImpl;

// 偏特化:根据onFinish的签名生成对应的实现
template<typename T, typename... Args>
struct CallbackImpl<T, void(T::*)(Args...)> : T {
    void onFinish(Args... args) override {
        _promise.set_value(std::make_tuple(std::forward<Args>(args)...));
    }

    auto&& promise() { return _promise; }
private:
    typename FuncTraits<void(T::*)(Args...)>::PromiseType _promise;
};

// 对应const版本的实现
template<typename T, typename... Args>
struct CallbackImpl<T, void(T::*)(Args...) const> : T {
    void onFinish(Args... args) const override {
        _promise.set_value(std::make_tuple(std::forward<Args>(args)...));
    }

    auto&& promise() const { return _promise; }
private:
    mutable typename FuncTraits<void(T::*)(Args...) const>::PromiseType _promise;
};

第二步:定义简化的别名模板

最后咱们给CallbackImpl套一个简单的别名,这样用起来就和你想要的一样了:

template<typename T>
using Callback = CallbackImpl<T>;

现在可以直接用简化写法了!

改造完成后,你只需要一行代码就能创建回调对象,编译器会自动帮你推导所有参数:

auto callback = std::make_shared<Callback<CallbackFilterProducts>>();
auto future = callback->promise().get_future();

一些补充说明

  • 这个方案兼容C++11及以上版本,主流编译器(GCC、Clang、MSVC)都支持。
  • 如果你的基类里有多个重载的onFinish函数,decltype(&T::onFinish)会产生歧义,这时候你需要手动指定要匹配的函数签名(比如用强制类型转换)。
  • 如果onFinish是const成员函数,咱们的特化版本也能正常处理,只需要把promise设为mutable,因为const成员函数不能修改非mutable成员。

这样改造后,代码简洁多了,完全满足你的需求!

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 03:34:54