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

能否在编译时存储模板方法的参数类型供类用户访问?

问题分析与解答

原代码不符合C++规范的原因

你的实现存在多处违反C++标准的问题,核心问题如下:

  1. 模板参数无法推导:run函数模板中的typename... New和typename... Old没有对应的推导上下文,调用run时编译器无法自动推导这些参数,必须显式指定,这显然违背了你想要自动累积类型的意图。
  2. constexpr变量不可修改:types_<T...>是constexpr静态成员,constexpr变量默认具备const属性,无法在运行时赋值(即使是constexpr赋值也需在编译期完成,而你的赋值操作位于运行时函数体内),这行代码会直接触发编译错误。
  3. 静态成员的共享性:静态成员属于类而非实例,所有User实例会共享同一组types_<T...>实例,无法实现每个实例独立存储自己的Event类型序列。

替代解决方案

根据你“存储每个实例调用run时的Event类型,供类用户访问”的需求,提供三种可行方案:

方案1:运行时类型追踪(简单易用)

如果只需要在运行时让用户查询哪些类型被传入过,直接用std::set<std::type_index>存储即可:

#include <set>
#include <typeindex>
#include <typeinfo>

class User {
public:
    template <typename Event>
    void run(const Event& event) {
        event_types_.insert(std::type_index(typeid(Event)));
        /* Do stuff.. */
    }

    // 对外暴露已存储的类型集合
    const std::set<std::type_index>& get_event_types() const {
        return event_types_;
    }

private:
    std::set<std::type_index> event_types_;
};

方案2:编译期+运行态结合的类型追踪

如果需要同时支持编译期类型访问和运行时类型记录,可以结合编译期类型列表和运行时类型索引:

#include <vector>
#include <typeindex>
#include <typeinfo>

// 编译期类型列表,用于静态层面的类型访问
template <typename... Ts>
struct TypeList {};

class User {
public:
    template <typename Event>
    void run(const Event& event) {
        // 运行时记录类型索引
        event_types_.push_back(std::type_index(typeid(Event)));
        /* Do stuff.. */
    }

    // 运行时获取所有Event类型的type_index列表
    const std::vector<std::type_index>& get_event_types() const {
        return event_types_;
    }

    // 编译期类型累积扩展:可通过外部元编程工具(如Boost.Mp11)实现动态扩展TypeList
    using CurrentEventTypes = TypeList<>;
private:
    std::vector<std::type_index> event_types_;
};

方案3:纯编译期类型累积(基于CRTP)

如果只需要在编译期访问累积的类型序列,可使用CRTP(奇异递归模板模式)实现实例级别的类型追踪:

template <typename... Ts>
struct TypeList {};

// CRTP基类,负责编译期类型累积
template <typename Derived, typename... AccumulatedEvents>
class EventTracker {
public:
    // 对外暴露当前累积的类型列表
    using EventTypes = TypeList<AccumulatedEvents...>;

    template <typename Event>
    void run(const Event& event) {
        // 转发到带累积类型参数的实现函数
        static_cast<Derived&>(*this).template run_impl<Event>(event);
        /* Do stuff.. */
    }

protected:
    // 核心实现:扩展类型列表并更新实例类型
    template <typename Event>
    void run_impl(const Event& event) {
        // 生成包含新Event类型的派生类版本
        using NewTracker = EventTracker<Derived, AccumulatedEvents..., Event>;
        // 可根据需求转移实例状态到新类型对象(需注意生命周期管理)
    }
};

// 用户类继承CRTP基类
class User : public EventTracker<User> {};

// 使用示例:编译期获取累积类型
void test() {
    User u;
    u.run(int{});
    u.run(double{});
    // 此时u的EventTypes为TypeList<int, double>
    using Events = decltype(u)::EventTypes;
}

内容的提问来源于stack exchange,提问作者fra.qrt

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 11:45:38