如何统一管理C++类集合并自动生成静态constexpr值到类的反向映射?
问题:基于序列化常量的类反向映射与批量操作自动化
场景说明
我有一组接口近似的可扩展类,每个类都包含一个用于序列化的唯一静态constexpr常量,示例如下:
class A { constexpr static int value = 0; }; class B { constexpr static int value = 1; };
当前实现的痛点
我目前通过手动编写模板特化实现从value到类的反向映射:
template <int value> struct type_for_value { }; template <> struct type_for_value<0> { using type = A; }; template <> struct type_for_value<1> { using type = B; };
但每次新增类(如类C)时,必须手动添加对应的模板特化。同时,遍历整个类集合的函数也需要同步修改参数包:
constexpr auto for_each_class(auto const& func) { return func.template operator()<A, B>(); }
需求
是否存在一种方案(优先使用参数包这类强类型实现,也可接受宏),只需一次性定义类集合,就能在编译时自动生成反向映射的模板特化,同时让批量遍历函数直接复用该集合?
我曾尝试用带参数包的结构体实现,但无法正确生成模板特化,且for_each_class的别名也无法正常工作:
template <typename... T> struct all_classes_impl { constexpr static auto for_each_class(auto const& func) { return func.template operator()<T...>(); } template <int value> struct type_for_value { }; template <> struct type_for_value<T::value> { using type = T; }...; }; using all_classes = all_classes_impl<A, B>; constexpr auto for_each_class = &all_classes::for_each_class;
可行解决方案
核心思路
利用参数包继承展开自动生成反向映射的模板特化,结合C++17折叠表达式实现批量遍历,只需维护一个类集合即可完成所有关联逻辑。
完整实现代码
#include <type_traits> #include <iostream> // 原始类定义(调整为public访问或添加友元确保value可被访问) class A { constexpr static int value = 0; public: static constexpr int get_value() { return value; } friend struct type_map_entry_helper<A>; }; class B { constexpr static int value = 1; public: static constexpr int get_value() { return value; } friend struct type_map_entry_helper<B>; }; // 基础模板:默认无对应类型 template <int value> struct type_map_entry { }; // 辅助模板:为单个类生成对应的type_map_entry特化 template <typename T> struct type_map_entry_helper : type_map_entry<T::value> { using type = T; }; // 类集合结构体:整合反向映射与批量操作 template <typename... Ts> struct class_collection : type_map_entry_helper<Ts>... { // 批量遍历:对每个类调用func的operator()<T> constexpr static void for_each(auto&& func) { (func.template operator()<Ts>(), ...); } // 反向映射:从value获取对应类类型 template <int value> using type_for_value = typename type_map_entry<value>::type; }; // 定义全局类集合 using all_classes = class_collection<A, B>;
使用示例
1. 反向映射验证
// 获取value=0对应的类 using TypeA = all_classes::type_for_value<0>; static_assert(std::is_same_v<TypeA, A>, "TypeA should be A"); // 获取value=1对应的类 using TypeB = all_classes::type_for_value<1>; static_assert(std::is_same_v<TypeB, B>, "TypeB should be B");
2. 批量遍历操作
// 定义处理单个类的函数对象 struct PrintClassValue { template <typename T> constexpr void operator()() const { std::cout << "Class value: " << T::get_value() << std::endl; } }; // 遍历所有类并输出value int main() { all_classes::for_each(PrintClassValue{}); return 0; } // 输出: // Class value: 0 // Class value: 1
新增类的便捷性
当新增类C时,只需修改all_classes的定义即可,无需修改其他逻辑:
class C { constexpr static int value = 2; public: static constexpr int get_value() { return value; } friend struct type_map_entry_helper<C>; }; // 更新类集合 using all_classes = class_collection<A, B, C>;
此时type_for_value<2>会自动映射到C,for_each也会自动遍历C。
关键细节说明
- 访问权限:如果类的
value是private的,需要将type_map_entry_helper<T>声明为友元,或者提供public的getter方法。 - 继承展开原理:
class_collection继承了type_map_entry_helper<Ts>...,每个type_map_entry_helper<T>会特化type_map_entry<T::value>并添加type成员,从而自动完成所有反向映射的特化。 - 折叠表达式:
(func.template operator()<Ts>(), ...)是C++17的折叠表达式,用于遍历参数包中的每个类型并执行函数调用。
内容的提问来源于stack exchange,提问作者Mark
相关产品推荐
相关产品推荐

