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

如何在编译时获取类的嵌套类列表并应用于模板参数包?

获取类的嵌套类型作为模板参数包的解决方案

好问题!不过很遗憾,直到C23,标准C都没有原生支持自动枚举一个类的所有嵌套类型的能力。不过我们有几种靠谱的替代方案,能满足你的需求,一起来看看:

方案一:手动注册嵌套类型(兼容性最好)

这是最直接、兼容性拉满的方式——我们手动把需要的嵌套类型整理成一个类型列表(比如用std::tuple),再通过辅助模板把列表展开为模板参数包。

示例代码:

#include <variant>
#include <tuple>

class Foo {
public:
    class FirstNested {};
    class SecondNested {};

    // 手动维护嵌套类型的类型列表,清晰可控
    using NestedTypes = std::tuple<FirstNested, SecondNested>;
};

// 辅助模板:把tuple的类型展开,应用到目标模板
template <class Tuple, template <class...> class Template>
struct ApplyTuple;

template <class... Ts, template <class...> class Template>
struct ApplyTuple<std::tuple<Ts...>, Template> {
    using type = Template<Ts...>;
};

// 简化别名,方便使用
template <class Tuple, template <class...> class Template>
using ApplyTuple_t = typename ApplyTuple<Tuple, Template>::type;

// 现在可以这样调用
ApplyTuple_t<Foo::NestedTypes, UsesFooNestedTypes> fooNestedTypesUser;

这种方式的好处是兼容所有C++版本,而且你可以精准控制哪些嵌套类型被包含(比如排除内部辅助类),完全不会出错。

方案二:用ADL配合标签类型(更灵活的分离式写法)

如果你不想把类型列表写在类内部,可以用ADL(参数依赖查找)配合标签类型来实现外部的类型列表注册:

#include <variant>
#include <tuple>

// 定义一个空的标签类型,用于触发ADL
struct get_nested_types_tag {};

class Foo {
public:
    class FirstNested {};
    class SecondNested {};
};

// 为Foo特化,提供它的嵌套类型列表
auto operator*(get_nested_types_tag, Foo) {
    return std::tuple<Foo::FirstNested, Foo::SecondNested>{};
}

// 复用之前的ApplyTuple辅助模板
template <class Tuple, template <class...> class Template>
struct ApplyTuple;

template <class... Ts, template <class...> class Template>
struct ApplyTuple<std::tuple<Ts...>, Template> {
    using type = Template<Ts...>;
};

template <class Tuple, template <class...> class Template>
using ApplyTuple_t = typename ApplyTuple<Tuple, Template>::type;

// 封装成更直观的别名
template <class T, template <class...> class Template>
using UsesNestedTypesOf = ApplyTuple_t<decltype(*(get_nested_types_tag{}, T{})), Template>;

// 使用方式更接近你的预期
UsesNestedTypesOf<Foo, UsesFooNestedTypes> fooNestedTypesUser;

这种写法把类型列表和类本身分离,适合需要在外部统一管理类型列表的场景,不过本质还是需要手动维护类型列表。

方案三:等待C++26的反射特性(未来可期)

如果能等的话,C++26的反射提案(比如P2996)会引入编译时反射能力,到时候就能自动枚举类的嵌套类型了。大致的假想用法如下:

// 仅为示例,基于C++26反射提案的假想代码
#include <reflect>
#include <variant>

// 过滤出类T的所有嵌套类类型
template <class T>
using get_nested_types_of = std::meta::filter<std::meta::members_of<T>, std::meta::is_class>;

// 直接实现你想要的调用方式
UsesFooNestedTypes<get_nested_types_of<Foo>> fooNestedTypesUser;

不过目前这个特性还在标准化阶段,暂时没法用到生产代码里。

针对你补充的状态模式场景的小建议

你提到后来创建了更具体的状态模式相关问题——其实手动注册的方式反而更适合这种场景:状态类通常不会频繁新增,维护成本很低,而且你可以精准控制哪些状态被纳入std::variant,避免把内部辅助类也加进去,反而更可控。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.28 18:12:29