如何用C++可变模板生成指定成员的类?
实现方法说明
首先要明确:你写的MyClass<int A, float B, char c>这种实例化方式不符合C++语法——模板参数列表中不能直接写int A这类"类型+变量名"的声明,模板参数只能是类型参数、非类型常量参数或模板参数。因此需要调整实现思路,以下是几种可行方案:
方案1:递归继承生成带命名成员的类
通过辅助模板封装单个成员,再用递归继承组合多个成员:
- 定义辅助结构体,用于封装单个成员的类型和唯一标识:
// C++20及以上支持auto非类型模板参数 template<typename T, auto UniqueTag> struct SingleMember { T member; };
- 定义递归组合的基类:
// 递归终止条件:空参数列表 template<typename... Args> struct MyClassBase {}; // 递归继承:每次继承一个SingleMember,再组合剩余成员 template<typename T, auto Tag, typename... Rest> struct MyClassBase<SingleMember<T, Tag>, Rest...> : SingleMember<T, Tag>, MyClassBase<Rest...> {};
- 用宏简化成员声明(避免手动写UniqueTag):
// 用lambda的地址作为唯一标识,每个lambda的地址编译期唯一 #define DEF_MEMBER(type, name) SingleMember<type, [](){}>
- 使用示例:
// 生成包含int A、float B、char c的类 using MyClass = MyClassBase<DEF_MEMBER(int, A), DEF_MEMBER(float, B), DEF_MEMBER(char, c)>; // 访问成员:需要指定基类,或者扩展MyClassBase添加using声明简化访问 MyClass obj; obj.SingleMember<int, [](){}>::member = 10;
如果希望直接用obj.A访问,可以通过宏生成带指定成员名的结构体再组合:
#define MAKE_MEMBER(type, name) \ struct Member_##name { \ type name; \ }; // 生成单个成员结构体 MAKE_MEMBER(int, A); MAKE_MEMBER(float, B); MAKE_MEMBER(char, c); // 递归继承组合 template<typename... Members> struct MyClass : Members... {}; // 使用 using MyClass = MyClass<Member_A, Member_B, Member_c>; MyClass obj; obj.A = 10; obj.B = 3.14f; obj.c = 'x';
方案2:用std::tuple结合结构化绑定(类似tuple的等价方案)
如果不需要显式的类成员名,只是想通过命名访问成员,C++17及以上的结构化绑定可以直接配合std::tuple实现:
#include <tuple> // 定义tuple类型,对应你需要的成员类型 using MyTuple = std::tuple<int, float, char>; // 使用时通过结构化绑定命名 MyTuple data{123, 4.56f, 'z'}; auto& [A, B, c] = data; // 直接用命名访问 A = 456; B = 7.89f; c = 'a';
这种方式不需要自定义类,利用标准库即可实现类似"命名成员"的访问效果。
方案3:纯宏实现(你提到的复杂宏方案)
通过宏展开直接生成类定义,适合简单场景:
#define DEF_CLASS(class_name, ...) \ class class_name { \ __VA_ARGS__ \ }; // 使用示例 DEF_CLASS(MyClass, int A; float B; char c; );
这种方式直接展开成你想要的类定义,缺点是缺乏模板的灵活性,但实现简单直接。
内容的提问来源于stack exchange,提问作者Jordan McBain
相关产品推荐
相关产品推荐

