CppCon 2021 学习:Beyond struct: Meta programming a struct Replacement in C++20
·
贴的这段 C++ 代码使用了 结构体 (struct) 和 C++20 的设计器初始化(designated initializer)。我帮你逐行解释一下:
struct person {
int id = 1; // 定义一个整型成员 id,默认值为 1
std::string name; // 定义一个字符串成员 name,没有默认值
int score = 0; // 定义一个整型成员 score,默认值为 0
};
struct person定义了一个名为person的结构体,里面有三个成员:id、name、score。id和score有默认值,name没有默认值,所以必须初始化。
int main() {
person p{.id = 1, .name = "John"}; // 使用 C++20 设计器初始化,给 id 和 name 赋初值
p是person类型的对象。.id = 1给id成员赋值 1,.name = "John"给name成员赋值"John"。- 由于
score有默认值 0,没有显式初始化,所以p.score = 0。
p.id = 2; // 修改 p 的 id 为 2
p.name = "JRB"; // 修改 p 的 name 为 "JRB"
- 这两行是对结构体成员的直接修改。
std::cout << p.id << " " << p.name;
}
- 打印输出当前
p的id和name,结果会是:
2 JRB
注意:如果你用的是 C++17 或更早的标准,.id = 1 这种设计器初始化是不支持的,需要写成:
person p{1, "John"}; // 按顺序初始化
总结:这段代码演示了结构体的定义、默认值、C++20设计器初始化以及修改成员,最终输出修改后的值。
#include <iostream>
#include <string>
struct person {
int id = 1;
std::string name;
int score = 0;
};
int main() {
person p{.id = 1, .name = "John"};
p.id = 2;
p.name = "JRB";
std::cout << p.id << " " << p.name;
}
1. 没有静态反射 (No static reflection)
- 意思:C++ 的
struct本身不能在编译期自动获取成员名字或类型。 - 说明:虽然有一些库(比如
magic_get)可以获取成员类型,但获取成员名字是不可能的。 - 例子:你不能写一个通用函数,自动把一个
struct转成 JSON,因为无法在编译期知道成员的名字。
2. 无法静态生成 (No static generation)
- 意思:无法根据名字自动生成一个新的
struct。 - 说明:例如,假如你有一个编译期的 JSON 字符串,C++ 无法直接把它解析成一个
struct类型的对象。
3. 没有必填成员 (No required members)
- 意思:C++
struct无法强制要求某些成员在构造时必须提供。 - 说明:你可以给成员默认值,也可以用构造函数初始化,但无法像一些高级语言那样声明“这个成员必须初始化”。
- 补充:可以通过包装类型(wrapper)实现类似功能,但 C++ 没有透明包装(transparent wrapper),所以不够灵活。
4. 设计器初始化器的顺序限制 (Designated initializers required to be in order, in C++ not C)
- 意思:在 C++ 中,如果使用 C++20 的 designated initializer,初始化的顺序必须和结构体声明的顺序一致。
- 说明:C 语言没有这个限制,可以任意顺序指定成员。
总结:
C++ 的struct很方便,但有以下限制:
- 不能在编译期获取成员名字 → 影响自动序列化等场景。
- 不能根据编译期数据自动生成新的
struct类型。 - 无法声明必填成员。
- C++ 的设计器初始化器必须按声明顺序。
#include <algorithm>
#include <cstddef>
// ----------------- 固定长度字符串模板 -----------------
template <std::size_t N>
struct fixed_string {
// 构造函数:把字符串字面量拷贝到内部数组
constexpr fixed_string(const char (&foo)[N + 1]) { std::copy_n(foo, N + 1, data); }
// 三路比较运算符(C++20),允许直接使用 ==, <, > 等操作
auto operator<=>(const fixed_string&) const = default;
char data[N + 1] = {}; // 存储字符串内容,末尾包含 '\0'
};
// 类模板参数自动推导 (CTAD),编译器根据字符串长度推导 N
template <std::size_t N>
fixed_string(const char (&str)[N]) -> fixed_string<N - 1>;
// ----------------- 成员模板 -----------------
template <fixed_string Tag, typename T>
struct member {
constexpr static auto tag() { return Tag; } // 返回成员的标签
using element_type = T; // 成员类型
T value; // 存储成员值
};
// ----------------- 元结构体模板 -----------------
template <typename... Members>
struct meta_struct : Members... {}; // 多继承所有成员
// ----------------- 获取成员值的辅助函数 -----------------
template <fixed_string tag, typename T>
decltype(auto) get_impl(member<tag, T>& m) {
return (m.value);
} // 非const 左值引用
template <fixed_string tag, typename T>
decltype(auto) get_impl(const member<tag, T>& m) {
return (m.value);
} // const 左值引用
template <fixed_string tag, typename T>
decltype(auto) get_impl(member<tag, T>&& m) {
return std::move(m.value);
} // 右值引用
// ----------------- 外部接口:根据标签获取成员 -----------------
template <fixed_string tag, typename MetaStruct>
decltype(auto) get(MetaStruct&& s) {
return get_impl<tag>(std::forward<MetaStruct>(s));
}
// ----------------- 使用示例 -----------------
#include <iostream>
#include <string>
int main() {
// 定义 Person 元结构体,包含两个成员:id 和 name
using Person = meta_struct<member<"id", int>, member<"name", std::string> >;
Person p; // 创建 Person 实例
get<"id">(p) = 1; // 设置 id
get<"name">(p) = "John"; // 设置 name
// 输出成员值
std::cout << get<"id">(p) << " " << get<"name">(p) << "\n";
}
当然,我来帮你用详细理解这段代码:
1⃣ fixed_string
template <std::size_t N>
struct fixed_string {
constexpr fixed_string(const char (&foo)[N + 1]) { std::copy_n(foo, N + 1, data); }
auto operator<=>(const fixed_string&) const = default;
char data[N + 1] = {};
};
template <std::size_t N>
fixed_string(const char (&str)[N]) -> fixed_string<N - 1>;
作用与理解:
- 用于在编译期保存字符串字面量,比如
"id"、"name"。 - 内部用
char data[N+1]存储字符,包含结尾的'\0'。 - 提供三路比较运算符
<=>,方便编译期比较两个fixed_string是否相等。 - 末尾的模板推导 (CTAD) 可以让编译器自动推导
N-1。
2⃣ member
template <fixed_string Tag, typename T>
struct member {
constexpr static auto tag() { return Tag; }
using element_type = T;
T value;
};
作用与理解:
- 将一个标签(编译期字符串)和类型绑定在一起。
Tag就是该成员的名字,例如"id"。value存储具体的成员值。- 可以通过
tag()获取这个成员的标签。
3⃣ meta_struct
template <typename... Members>
struct meta_struct : Members... {};
作用与理解:
- 使用多继承把多个
member组合成一个“结构体”。 - 举例:
就是把using Person = meta_struct< member<"id", int>, member<"name", std::string> >;id和name组合到一起形成Person类型。
4⃣ get_impl 和 get
template <fixed_string tag, typename T>
decltype(auto) get_impl(member<tag, T>& m) { return (m.value); }
template <fixed_string tag, typename T>
decltype(auto) get_impl(const member<tag, T>& m) { return (m.value); }
template <fixed_string tag, typename T>
decltype(auto) get_impl(member<tag, T>&& m) { return std::move(m.value); }
template <fixed_string tag, typename MetaStruct>
decltype(auto) get(MetaStruct&& s) { return get_impl<tag>(std::forward<MetaStruct>(s)); }
作用与理解:
get_impl根据标签tag获取member中的value值。- 提供三种重载,支持:
- 左值引用
- const 左值引用
- 右值引用(可以直接移动值)
get<tag>(instance)是外部接口,用于通过标签访问成员值,非常像instance.id或instance.name,但是是编译期安全索引。
5⃣ 使用示例
using Person = meta_struct<member<"id", int>, member<"name", std::string>>;
Person p;
get<"id">(p) = 1;
get<"name">(p) = "John";
std::cout << get<"id">(p) << " " << get<"name">(p) << "\n";
理解:
- 定义一个
Person类型,包含两个成员:id(int)和name(string)。 - 创建
Person p实例。 - 用
get<"id">(p)和get<"name">(p)设置成员值。 - 输出成员值,结果是:
1 John
总结:
- 这是一种编译期元编程实现的结构体成员访问方法。
- 优点:
- 标签在编译期确定,安全性高
- 可支持模板化和元编程场景
- 缺点:
- 实现比普通
struct复杂 - 调试时信息可能不直观
- 实现比普通
#include <algorithm>
#include <cstddef>
// ----------------- 固定长度字符串包装,用作模板非类型参数 -----------------
template <std::size_t N>
struct fixed_string {
// 构造函数:将传入的字符串拷贝到 data 数组中
constexpr fixed_string(const char (&foo)[N + 1]) { std::copy_n(foo, N + 1, data); }
// 三向比较运算符,方便比较 fixed_string 对象
auto operator<=>(const fixed_string&) const = default;
char data[N + 1] = {}; // 存储字符串内容
};
// 推导向导:将 const char[N] 自动转换为 fixed_string<N-1>
template <std::size_t N>
fixed_string(const char (&str)[N]) -> fixed_string<N - 1>;
// ----------------- 标签和值组合 -----------------
template <fixed_string Tag, typename T>
struct tag_and_value {
T value; // 存储值
};
// ----------------- 参数包,用于传递初始化参数 -----------------
template <typename... TagsAndValues>
struct parms : TagsAndValues... {}; // 继承所有 tag_and_value,实现聚合
template <typename... TagsAndValues>
parms(TagsAndValues...) -> parms<TagsAndValues...>; // 推导向导
// ----------------- 创建标签类型,方便写法 arg<"id"> = 1 -----------------
template <fixed_string Tag>
struct arg_type {
template <typename T>
constexpr auto operator=(T t) const {
return tag_and_value<Tag, T>{std::move(t)}; // 返回 tag_and_value 对象
}
};
template <fixed_string Tag>
inline constexpr auto arg = arg_type<Tag>{}; // 全局常量,方便直接使用
// ----------------- 元成员定义 -----------------
template <fixed_string Tag, typename T>
struct member {
constexpr static auto tag() { return Tag; } // 获取标签
using element_type = T; // 类型别名
T value; // 存储值
// 使用 tag_and_value 初始化成员
template <typename OtherT>
constexpr member(tag_and_value<Tag, OtherT> tv) : value(std::move(tv.value)) {}
// 默认构造、拷贝、移动
constexpr member() = default;
constexpr member(member&&) = default;
constexpr member(const member&) = default;
constexpr member& operator=(member&&) = default;
constexpr member& operator=(const member&) = default;
auto operator<=>(const member&) const = default; // 三向比较
};
// ----------------- 元结构体实现层 -----------------
template <typename... Members>
struct meta_struct_impl : Members... { // 继承所有成员
// 用 parms 初始化所有成员
template <typename Parms>
constexpr meta_struct_impl(Parms p) : Members(std::move(p))... {}
// 默认构造、拷贝、移动
constexpr meta_struct_impl() = default;
constexpr meta_struct_impl(meta_struct_impl&&) = default;
constexpr meta_struct_impl(const meta_struct_impl&) = default;
constexpr meta_struct_impl& operator=(meta_struct_impl&&) = default;
constexpr meta_struct_impl& operator=(const meta_struct_impl&) = default;
auto operator<=>(const meta_struct_impl&) const = default;
};
// ----------------- 元结构体外层接口 -----------------
template <typename... Members>
struct meta_struct : meta_struct_impl<Members...> {
using super = meta_struct_impl<Members...>;
// 支持按标签初始化
template <typename... TagsAndValues>
constexpr meta_struct(TagsAndValues... tags_and_values)
: super(parms(std::move(tags_and_values)...)) {}
// 默认构造、拷贝、移动
constexpr meta_struct() = default;
constexpr meta_struct(meta_struct&&) = default;
constexpr meta_struct(const meta_struct&) = default;
constexpr meta_struct& operator=(meta_struct&&) = default;
constexpr meta_struct& operator=(const meta_struct&) = default;
auto operator<=>(const meta_struct&) const = default;
};
// ----------------- get 函数:通过标签获取成员值 -----------------
template <fixed_string tag, typename T>
decltype(auto) get_impl(member<tag, T>& m) {
return (m.value);
}
template <fixed_string tag, typename T>
decltype(auto) get_impl(const member<tag, T>& m) {
return (m.value);
}
template <fixed_string tag, typename T>
decltype(auto) get_impl(member<tag, T>&& m) {
return std::move(m.value);
}
template <fixed_string tag, typename MetaStruct>
decltype(auto) get(MetaStruct&& s) {
return get_impl<tag>(std::forward<MetaStruct>(s));
}
// ----------------- 测试用例 -----------------
#include <iostream>
#include <string>
int main() {
// 定义一个 Person 元结构体,包含 id 和 name 两个成员
using Person = meta_struct<member<"id", int>, member<"name", std::string> >;
// 使用标签初始化顺序无关
Person p{arg<"id"> = 1, arg<"name"> = "John"};
std::cout << get<"id">(p) << " " << get<"name">(p) << "\n";
// 改变顺序初始化,依然正确
p = Person{arg<"name"> = "John", arg<"id"> = 1};
std::cout << get<"id">(p) << " " << get<"name">(p) << "\n";
}
详细理解这段代码的逻辑和实现原理:
1⃣ fixed_string:编译期字符串包装
template <std::size_t N>
struct fixed_string {
constexpr fixed_string(const char (&foo)[N + 1]) { std::copy_n(foo, N + 1, data); }
auto operator<=>(const fixed_string&) const = default;
char data[N + 1] = {};
};
- 用途:在 编译期 将字符串包装为类型参数(非类型模板参数),这样可以用
"id"、"name"作为模板参数。 operator<=>提供比较能力。data保存实际字符串内容。- 推导向导允许
fixed_string("abc")自动生成类型fixed_string<3>。
2⃣ tag_and_value:标签与值组合
template <fixed_string Tag, typename T>
struct tag_and_value {
T value;
};
- 作用:把标签和实际值打包在一起,方便传递给成员初始化。
3⃣ parms:参数包
template <typename... TagsAndValues>
struct parms : TagsAndValues... {};
- 聚合多个
tag_and_value,实现批量初始化。 - 是 多继承,所以可以按类型区分不同标签。
4⃣ arg<"id"> = value:语法糖
template <fixed_string Tag>
struct arg_type {
template <typename T>
constexpr auto operator=(T t) const {
return tag_and_value<Tag, T>{std::move(t)};
}
};
template <fixed_string Tag>
inline constexpr auto arg = arg_type<Tag>{};
arg<"id"> = 1会生成tag_and_value<"id", int>{1}。- 方便使用,不必手动写
tag_and_value。
5⃣ member:元结构体的成员
template <fixed_string Tag, typename T>
struct member {
T value;
template <typename OtherT>
constexpr member(tag_and_value<Tag, OtherT> tv) : value(std::move(tv.value)) {}
};
- 每个
member对应一个标签(Tag)和类型(T)。 - 可以用
tag_and_value初始化。 - 默认构造、拷贝、移动,支持比较运算。
6⃣ meta_struct_impl:实现层
template <typename... Members>
struct meta_struct_impl : Members... {
template <typename Parms>
constexpr meta_struct_impl(Parms p) : Members(std::move(p))... {}
};
- 继承所有成员,实现 多继承聚合。
- 构造函数可接受一个
parms对象,把每个tag_and_value分发给对应的member。 - 也支持默认构造、拷贝、移动。
7⃣ meta_struct:对外接口
template <typename... Members>
struct meta_struct : meta_struct_impl<Members...> {
template <typename... TagsAndValues>
constexpr meta_struct(TagsAndValues... tags_and_values)
: super(parms(std::move(tags_and_values)...)) {}
};
- 提供对外可用的接口,允许 按标签初始化,顺序无关。
- 可以通过
arg<"id"> = 1的语法初始化。
8⃣ get 函数:通过标签获取值
template <fixed_string tag, typename MetaStruct>
decltype(auto) get(MetaStruct&& s) {
return get_impl<tag>(std::forward<MetaStruct>(s));
}
get<"id">(p)会找到对应member<"id", T>并返回其value。- 支持左值、右值和 const 对象。
9⃣ 测试用例
using Person = meta_struct<member<"id", int>, member<"name", std::string>>;
Person p{arg<"id"> = 1, arg<"name"> = "John"};
std::cout << get<"id">(p) << " " << get<"name">(p) << "\n";
p = Person{arg<"name"> = "John", arg<"id"> = 1};
std::cout << get<"id">(p) << " " << get<"name">(p) << "\n";
- 定义一个
Person元结构体,成员为id和name。 - 初始化可以顺序无关,通过标签匹配。
get<"id">获取值。- 输出:
1 John
1 John
核心思想总结
- 编译期字符串 + 模板 实现标签。
- 多继承 + 参数包 实现成员聚合。
- 标签初始化:顺序无关,通过
arg<"tag"> = value生成tag_and_value。 - get 函数:通过标签访问成员,实现类似 编译期反射。
解释每一部分的作用和原理:
#include <algorithm>
#include <cstddef>
#include <type_traits>
// ----------------- 固定长度字符串包装,用作模板非类型参数 -----------------
template <std::size_t N>
struct fixed_string {
// 构造函数:将传入的字符串拷贝到 data 数组中
constexpr fixed_string(const char (&foo)[N + 1]) {
std::copy_n(foo, N + 1, data);
}
// 三向比较运算符,方便 fixed_string 对象比较
auto operator<=>(const fixed_string&) const = default;
char data[N + 1] = {}; // 保存字符串内容,末尾有 '\0'
};
// 推导向导:允许 const char[N] 自动转换为 fixed_string<N-1>
template <std::size_t N>
fixed_string(const char (&str)[N]) -> fixed_string<N - 1>;
// ----------------- 标签和值组合,用于初始化成员 -----------------
template <fixed_string Tag, typename T>
struct tag_and_value {
T value; // 存储对应标签的值
};
// ----------------- 参数包,用于聚合多个 tag_and_value -----------------
template <typename... TagsAndValues>
struct parms : TagsAndValues... {};
// 参数包推导向导
template <typename... TagsAndValues>
parms(TagsAndValues...) -> parms<TagsAndValues...>;
// ----------------- 创建标签类型,用于语法糖 arg<"id"> = 1 -----------------
template <fixed_string Tag>
struct arg_type {
template <typename T>
constexpr auto operator=(T t) const {
// 返回 tag_and_value 对象,用于初始化 member
return tag_and_value<Tag, T>{std::move(t)};
}
};
// 全局常量,方便直接使用
template <fixed_string Tag>
inline constexpr auto arg = arg_type<Tag>{};
// ----------------- 默认初始化器 -----------------
template <typename T>
struct default_init {
constexpr default_init() = default;
auto operator<=>(const default_init&) const = default;
constexpr auto operator()() const {
if constexpr (std::is_default_constructible_v<T>) {
return T{}; // 默认构造类型 T
}
}
};
// ----------------- 元成员定义 -----------------
template <fixed_string Tag, typename T, auto Init = default_init<T>()>
struct member {
constexpr static auto tag() { return Tag; } // 获取标签
constexpr static auto init() { return Init; } // 获取初始化器
using element_type = T; // 类型别名
T value; // 存储值
// 使用 tag_and_value 初始化成员
template <typename OtherT>
constexpr member(tag_and_value<Tag, OtherT> tv)
: value(std::move(tv.value)) {}
// 默认构造时使用 Init 初始化
constexpr member() : value(Init()) {}
// 默认拷贝、移动构造和赋值
constexpr member(member&&) = default;
constexpr member(const member&) = default;
constexpr member& operator=(member&&) = default;
constexpr member& operator=(const member&) = default;
auto operator<=>(const member&) const = default; // 三向比较
};
// ----------------- 元结构体实现层 -----------------
template <typename... Members>
struct meta_struct_impl : Members... {
// 使用参数包初始化所有成员
template <typename Parms>
constexpr meta_struct_impl(Parms p) : Members(std::move(p))... {}
// 默认构造、拷贝、移动
constexpr meta_struct_impl() = default;
constexpr meta_struct_impl(meta_struct_impl&&) = default;
constexpr meta_struct_impl(const meta_struct_impl&) = default;
constexpr meta_struct_impl& operator=(meta_struct_impl&&) = default;
constexpr meta_struct_impl& operator=(const meta_struct_impl&) = default;
auto operator<=>(const meta_struct_impl&) const = default; // 三向比较
};
// ----------------- 元结构体外层接口 -----------------
template <typename... Members>
struct meta_struct : meta_struct_impl<Members...> {
using super = meta_struct_impl<Members...>;
// 支持按标签初始化
template <typename... TagsAndValues>
constexpr meta_struct(TagsAndValues... tags_and_values)
: super(parms(std::move(tags_and_values)...)) {}
// 默认构造、拷贝、移动
constexpr meta_struct() = default;
constexpr meta_struct(meta_struct&&) = default;
constexpr meta_struct(const meta_struct&) = default;
constexpr meta_struct& operator=(meta_struct&&) = default;
constexpr meta_struct& operator=(const meta_struct&) = default;
auto operator<=>(const meta_struct&) const = default;
};
// ----------------- get 函数:通过标签获取成员值 -----------------
template <fixed_string tag, typename T, auto Init>
decltype(auto) get_impl(member<tag, T, Init>& m) {
return (m.value);
}
template <fixed_string tag, typename T, auto Init>
decltype(auto) get_impl(const member<tag, T, Init>& m) {
return (m.value);
}
template <fixed_string tag, typename T, auto Init>
decltype(auto) get_impl(member<tag, T, Init>&& m) {
return std::move(m.value);
}
template <fixed_string tag, typename MetaStruct>
decltype(auto) get(MetaStruct&& s) {
return get_impl<tag>(std::forward<MetaStruct>(s));
}
// ----------------- 测试用例 -----------------
#include <iostream>
#include <string>
int main() {
// 定义一个 Person 元结构体,包含 id 和 name
// 注意 name 有一个 lambda 默认值 "John"
using Person = meta_struct< //
member<"id", int>, //
member<"name", std::string, [] { return "John"; }> //
>;
Person p; // 默认构造,id = int{} = 0, name = "John"
std::cout << get<"id">(p) << " " << get<"name">(p) << "\n";
// 输出:0 John
}
核心理解:
- fixed_string:用于编译期字符串,作为模板非类型参数。
- arg<“tag”> = value:生成
tag_and_value对象,用于按标签初始化。 - member:每个元结构体成员,支持默认值和按标签初始化。
- meta_struct:将多个成员聚合,提供顺序无关的初始化。
- get<“tag”>(obj):通过标签获取成员值,实现类似编译期反射。
- 默认初始化 lambda:可以在定义 member 时指定默认值,比如
name的"John"。
1⃣ 固定长度字符串 fixed_string
template <std::size_t N>
struct fixed_string {
constexpr fixed_string(const char (&foo)[N + 1]) { std::copy_n(foo, N + 1, data); }
auto operator<=>(const fixed_string&) const = default;
char data[N + 1] = {};
};
- 用途:在 C++20 中,模板非类型参数(NTTP)允许使用编译期固定长度字符串。
- data:保存字符串内容,末尾自动加
\0。 - 三向比较:
<=>用于比较两个fixed_string,便于在模板中使用。
template <std::size_t N>
fixed_string(const char (&str)[N]) -> fixed_string<N - 1>;
- 推导向导:让
"id"这样的字符串自动变成fixed_string<2>(去掉末尾\0)。
2⃣ 标签和值组合 tag_and_value
template <fixed_string Tag, typename T>
struct tag_and_value {
T value;
};
- 用于存储某个标签对应的值,比如
arg<"id"> = 1会生成tag_and_value<"id", int>。
3⃣ 参数包 parms
template <typename... TagsAndValues>
struct parms : TagsAndValues... {};
template <typename... TagsAndValues>
parms(TagsAndValues...) -> parms<TagsAndValues...>;
- 作用:聚合多个
tag_and_value,并继承它们,使得可以同时初始化多个成员。 - 推导向导:让
parms(arg<"id">=1, arg<"name">="John")自动推导类型。
4⃣ 标签语法糖 arg<"id">
template <fixed_string Tag>
struct arg_type {
template <typename T>
constexpr auto operator=(T t) const {
return tag_and_value<Tag, T>{std::move(t)};
}
};
template <fixed_string Tag>
inline constexpr auto arg = arg_type<Tag>{};
- 目的是让初始化时写法变得直观:
Person p{arg<"id">=1, arg<"name">="John"}; operator=返回tag_and_value,用于 member 构造。
5⃣ 默认初始化器 default_init
template <typename T>
struct default_init {
constexpr auto operator()() const {
if constexpr (std::is_default_constructible_v<T>) {
return T{};
}
}
};
- 如果成员没有显式提供值,会使用默认构造器。
- 支持在 member 中指定 lambda 作为默认值,例如
member<"name", std::string, []{ return "John"; }>。
6⃣ 元成员 member
template <fixed_string Tag, typename T, auto Init = default_init<T>()>
struct member {
T value;
constexpr member() : value(Init()) {} // 默认构造时使用 Init
template <typename OtherT>
constexpr member(tag_and_value<Tag, OtherT> tv) : value(std::move(tv.value)) {}
};
- Tag:标签
- T:类型
- Init:初始化器(lambda 或默认构造器)
- 支持 按标签初始化 或 默认构造。
7⃣ 元结构体实现层 meta_struct_impl
template <typename... Members>
struct meta_struct_impl : Members... {
template <typename Parms>
constexpr meta_struct_impl(Parms p) : Members(std::move(p))... {}
};
- 继承所有成员,使得
meta_struct_impl拥有多个成员变量。 - 使用参数包初始化每个成员。
8⃣ 元结构体外层接口 meta_struct
template <typename... Members>
struct meta_struct : meta_struct_impl<Members...> {
template <typename... TagsAndValues>
constexpr meta_struct(TagsAndValues... tags_and_values)
: meta_struct_impl<Members...>(parms(std::move(tags_and_values)...)) {}
};
- 允许按标签初始化,顺序无关。
- 默认构造也可用。
9⃣ get 函数
template <fixed_string tag, typename T, auto Init>
decltype(auto) get_impl(member<tag, T, Init>& m) { return m.value; }
template <fixed_string tag, typename MetaStruct>
decltype(auto) get(MetaStruct&& s) { return get_impl<tag>(std::forward<MetaStruct>(s)); }
- 作用:通过标签访问成员值,如
get<"id">(p)返回p.value。
🔟 测试用例
using Person = meta_struct<
member<"id", int>,
member<"name", std::string, [] { return "John"; }>
>;
Person p; // 默认构造 id = 0, name = "John"
std::cout << get<"id">(p) << " " << get<"name">(p) << "\n";
- 输出:
0 John - 支持按标签初始化顺序无关:
Person p2{arg<"name">="Alice", arg<"id">=42};
总结理解:
- 使用
fixed_string作为标签,实现编译期标签系统。 arg<"tag">=value生成tag_and_value,用于按标签初始化成员。member可带默认值或显式初始化。meta_struct聚合多个 member,支持顺序无关的初始化。get<"tag">()通过标签访问成员,实现类似编译期反射。
#include <algorithm>
#include <cstddef>
#include <type_traits>
// ----------------- 固定长度字符串包装,用作模板非类型参数 -----------------
template <std::size_t N>
struct fixed_string {
// 构造函数:将传入的字符串拷贝到 data 数组中
constexpr fixed_string(const char (&foo)[N + 1]) { std::copy_n(foo, N + 1, data); }
// 三向比较运算符,方便 fixed_string 对象比较
constexpr auto operator<=>(const fixed_string&) const = default;
char data[N + 1] = {}; // 保存字符串内容,末尾有 '\0'
};
// 推导向导:允许 const char[N] 自动转换为 fixed_string<N-1>
template <std::size_t N>
fixed_string(const char (&str)[N]) -> fixed_string<N - 1>;
// ----------------- 标签和值组合,用于初始化成员 -----------------
template <fixed_string Tag, typename T>
struct tag_and_value {
T value; // 存储标签对应的值
};
// ----------------- 参数包,用于聚合多个 tag_and_value -----------------
template <typename... TagsAndValues>
struct parms : TagsAndValues... {};
template <typename... TagsAndValues>
parms(TagsAndValues...) -> parms<TagsAndValues...>; // 推导向导
// ----------------- 创建标签类型,用于语法糖 arg<"id"> = 1 -----------------
template <fixed_string Tag>
struct arg_type {
template <typename T>
constexpr auto operator=(T t) const {
return tag_and_value<Tag, T>{std::move(t)}; // 返回 tag_and_value 对象
}
};
template <fixed_string Tag>
inline constexpr auto arg = arg_type<Tag>{}; // 全局常量,方便直接使用
// ----------------- 默认初始化器 -----------------
template <typename T>
struct default_init {
constexpr default_init() = default;
constexpr auto operator<=>(const default_init&) const = default;
// 默认构造对象,如果 T 可默认构造
constexpr auto operator()() const {
if constexpr (std::is_default_constructible_v<T>) {
return T{};
}
}
};
// ----------------- 带依赖的初始化函数 -----------------
// 支持 Init() 或 Init(self) 两种形式的初始化
template <typename T, typename Self, typename F>
auto call_init(Self&, F& f)
requires(requires { { f() } -> std::convertible_to<T>; })
{
return f(); // 调用无参数初始化
}
template <typename T, typename Self, typename F>
auto call_init(Self& self, F& f)
requires(requires { { f(self) } -> std::convertible_to<T>; })
{
return f(self); // 调用带 self 参数的初始化
}
// 支持返回 void 的初始化器(不做任何事)
template <typename T, typename Self, typename F>
auto call_init(Self& self, F& f)
requires(requires { { f() } -> std::same_as<void>; })
{}
// ----------------- 元成员定义 -----------------
template <fixed_string Tag, typename T, auto Init = default_init<T>()>
struct member {
constexpr static auto tag() { return Tag; } // 获取标签
constexpr static auto init() { return Init; } // 获取初始化器
using element_type = T; // 类型别名
T value; // 存储值
// 使用 tag_and_value 初始化成员
template <typename OtherT>
constexpr member(tag_and_value<Tag, OtherT> tv) : value(std::move(tv.value)) {}
// 默认构造:使用 Init 初始化
template <typename Self>
constexpr member(Self& self) : value(call_init<T>(self, Init)) {}
// 默认拷贝、移动构造和赋值
constexpr member(member&&) = default;
constexpr member(const member&) = default;
constexpr member& operator=(member&&) = default;
constexpr member& operator=(const member&) = default;
auto operator<=>(const member&) const = default; // 三向比较
};
// ----------------- 元结构体实现层 -----------------
template <typename... Members>
struct meta_struct_impl : Members... {
// 使用参数包初始化所有成员
template <typename Parms>
constexpr meta_struct_impl(Parms p) : Members(std::move(p))... {}
// 默认构造:依次调用每个 member(Self&)
constexpr meta_struct_impl() : Members(*this)... {}
// 默认拷贝、移动构造和赋值
constexpr meta_struct_impl(meta_struct_impl&&) = default;
constexpr meta_struct_impl(const meta_struct_impl&) = default;
constexpr meta_struct_impl& operator=(meta_struct_impl&&) = default;
constexpr meta_struct_impl& operator=(const meta_struct_impl&) = default;
auto operator<=>(const meta_struct_impl&) const = default; // 三向比较
};
// ----------------- 元结构体外层接口 -----------------
template <typename... Members>
struct meta_struct : meta_struct_impl<Members...> {
using super = meta_struct_impl<Members...>;
// 支持按标签初始化
template <typename... TagsAndValues>
constexpr meta_struct(TagsAndValues... tags_and_values)
: super(parms(std::move(tags_and_values)...)) {}
constexpr meta_struct() = default;
constexpr meta_struct(meta_struct&&) = default;
constexpr meta_struct(const meta_struct&) = default;
constexpr meta_struct& operator=(meta_struct&&) = default;
constexpr meta_struct& operator=(const meta_struct&) = default;
auto operator<=>(const meta_struct&) const = default;
};
// ----------------- get 函数:通过标签获取成员值 -----------------
template <fixed_string tag, typename T, auto Init>
decltype(auto) get_impl(member<tag, T, Init>& m) {
return (m.value);
}
template <fixed_string tag, typename T, auto Init>
decltype(auto) get_impl(const member<tag, T, Init>& m) {
return (m.value);
}
template <fixed_string tag, typename T, auto Init>
decltype(auto) get_impl(member<tag, T, Init>&& m) {
return std::move(m.value);
}
template <fixed_string tag, typename MetaStruct>
decltype(auto) get(MetaStruct&& s) {
return get_impl<tag>(std::forward<MetaStruct>(s));
}
// ----------------- 测试用例 -----------------
#include <iostream>
#include <string>
int main() {
// 定义一个 Person 元结构体
// id 使用默认初始化 0
// score 依赖 id 初始化,值为 id+1
// name 默认初始化为 "John"
using Person = meta_struct<
member<"id", int>,
member<"score", int, [](auto& self) { return get<"id">(self) + 1; }>,
member<"name", std::string, [] { return "John"; }>
>;
Person p; // 默认构造
// 输出:id = 0, name = John, score = 1
std::cout << get<"id">(p) << " "
<< get<"name">(p) << " "
<< get<"score">(p) << "\n";
}
关键点理解
- 固定字符串标签
fixed_string让标签在编译期确定,可用于模板非类型参数。 - 按标签初始化:通过
arg<"tag">=value构造成员。 - 默认初始化器
default_init或 lambda 支持成员自定义默认值。 - 依赖初始化:score 的 lambda 可以访问
self,即整个结构体对象,实现“成员依赖其他成员初始化”。 - get 函数:编译期根据标签获取成员值,实现类似编译期反射。
实现了一个 编译期“元结构体” 的框架,支持 标签初始化、默认值、依赖其他成员的初始化,类似于 C++ 的“轻量型反射”。我帮你整理一下核心理解:
1⃣ fixed_string
template <std::size_t N>
struct fixed_string {
constexpr fixed_string(const char (&foo)[N + 1]) { std::copy_n(foo, N + 1, data); }
constexpr auto operator<=>(const fixed_string&) const = default;
char data[N + 1] = {};
};
- 用于 编译期字符串,可作为模板非类型参数。
- 支持三向比较
<=>,可以在模板参数中比较标签。 - 推导向导
fixed_string(const char (&str)[N]) -> fixed_string<N-1>,让"id"可以直接作为模板参数。
2⃣ tag_and_value 与 arg<"tag"> = value 语法糖
template <fixed_string Tag, typename T>
struct tag_and_value { T value; };
template <fixed_string Tag>
struct arg_type {
template <typename T>
constexpr auto operator=(T t) const { return tag_and_value<Tag, T>{std::move(t)}; }
};
template <fixed_string Tag>
inline constexpr auto arg = arg_type<Tag>{};
tag_and_value存储某个标签对应的值。arg<"id"> = 1是语法糖,返回tag_and_value<"id", int>{1}。
3⃣ default_init 和 call_init
template <typename T>
struct default_init { ... };
template <typename T, typename Self, typename F>
auto call_init(Self& self, F& f) { ... }
default_init<T>:提供类型 T 的默认构造值。call_init支持:- 无参数初始化
Init() - 带结构体引用初始化
Init(self),允许依赖其他成员 - 返回
void的初始化器忽略
- 无参数初始化
4⃣ member 元成员
template <fixed_string Tag, typename T, auto Init = default_init<T>()>
struct member {
T value;
template <typename OtherT>
constexpr member(tag_and_value<Tag, OtherT> tv) : value(std::move(tv.value)) {}
template <typename Self>
constexpr member(Self& self) : value(call_init<T>(self, Init)) {}
};
- 每个成员都有一个 标签 和 值类型 T。
- 支持 直接初始化(tag_and_value)或 默认初始化(Init 或 lambda)。
- 可以访问整个结构体
self来初始化依赖成员。
5⃣ meta_struct_impl 和 meta_struct
template <typename... Members>
struct meta_struct_impl : Members... {
constexpr meta_struct_impl() : Members(*this)... {} // 默认构造
};
template <typename... Members>
struct meta_struct : meta_struct_impl<Members...> { ... };
- 继承所有成员,实现 成员聚合。
- 默认构造时,每个成员可以通过
member(Self&)初始化依赖。 meta_struct是外层接口,支持按标签初始化。
6⃣ get 函数
template <fixed_string tag, typename MetaStruct>
decltype(auto) get(MetaStruct&& s) {
return get_impl<tag>(std::forward<MetaStruct>(s));
}
- 通过标签获取成员值。
- 支持左值、右值和 const 左值。
7⃣ 测试用例
using Person = meta_struct<
member<"id", int>,
member<"score", int, [](auto& self) { return get<"id">(self) + 1; }>,
member<"name", std::string, [] { return "John"; }>
>;
Person p;
std::cout << get<"id">(p) << " " << get<"name">(p) << " " << get<"score">(p) << "\n";
id使用默认值0name使用默认值"John"score依赖id初始化,结果为id+1 = 1- 输出:
0 John 1
核心概念
- 编译期标签 + 元结构体:实现类似反射的访问方式。
- 成员依赖初始化:通过
Self&lambda 可以让一个成员依赖其他成员。 - 灵活初始化:支持标签初始化和默认初始化,顺序无关。
#include <algorithm>
#include <cstddef>
#include <string_view>
#include <type_traits>
// ----------------- 固定长度字符串包装,用作模板非类型参数 -----------------
template <std::size_t N>
struct fixed_string {
// 构造函数:将传入的字符串拷贝到 data 数组中
constexpr fixed_string(const char (&foo)[N + 1]) { std::copy_n(foo, N + 1, data); }
// 支持 string_view 构造,允许从 std::string_view 初始化
constexpr fixed_string(std::string_view s) {
static_assert(s.size() <= N); // 确保不会越界
std::copy(s.begin(), s.end(), data);
}
// 获取字符串视图
constexpr std::string_view sv() const { return std::string_view(data); }
auto operator<=>(const fixed_string&) const = default; // 三向比较
char data[N + 1] = {}; // 保存字符串内容,末尾 '\0'
};
// 推导向导:允许 const char[N] 自动转换为 fixed_string<N-1>
template <std::size_t N>
fixed_string(const char (&str)[N]) -> fixed_string<N - 1>;
// ----------------- 标签和值组合,用于初始化成员 -----------------
template <fixed_string Tag, typename T>
struct tag_and_value {
T value; // 存储标签对应的值
};
// ----------------- 参数包,用于聚合多个 tag_and_value -----------------
template <typename... TagsAndValues>
struct parms : TagsAndValues... {}; // 多重继承,实现聚合
template <typename... TagsAndValues>
parms(TagsAndValues...) -> parms<TagsAndValues...>; // 推导向导
// ----------------- 创建标签类型,用于语法糖 arg<"id"> = 1 -----------------
template <fixed_string Tag>
struct arg_type {
template <typename T>
constexpr auto operator=(T t) const {
return tag_and_value<Tag, T>{std::move(t)}; // 返回 tag_and_value 对象
}
};
template <fixed_string Tag>
inline constexpr auto arg = arg_type<Tag>{}; // 全局常量,方便直接使用
// ----------------- 默认初始化器 -----------------
template <typename T>
struct default_init {
constexpr default_init() = default;
auto operator<=>(const default_init&) const = default;
// 默认构造对象,如果 T 可默认构造
constexpr auto operator()() const {
if constexpr (std::is_default_constructible_v<T>) {
return T{};
}
}
};
// ----------------- 支持依赖结构体的初始化函数 -----------------
// 支持 Init() 或 Init(self) 两种形式
template <typename T, typename Self, typename F>
auto call_init(Self&, F& f)
requires(requires { { f() } -> std::convertible_to<T>; })
{
return f(); // 无参数初始化
}
template <typename T, typename Self, typename F>
auto call_init(Self& self, F& f)
requires(requires { { f(self) } -> std::convertible_to<T>; })
{
return f(self); // 带 self 参数初始化,允许依赖其他成员
}
// 支持返回 void 的初始化器,不做任何事
template <typename T, typename Self, typename F>
auto call_init(Self& self, F& f)
requires(requires { { f() } -> std::same_as<void>; })
{}
// ----------------- 元成员定义 -----------------
template <fixed_string Tag, typename T, auto Init = default_init<T>()>
struct member {
constexpr static auto tag() { return Tag; } // 获取标签
constexpr static auto init() { return Init; } // 获取初始化器
using element_type = T; // 类型别名
T value; // 存储成员值
// 使用 tag_and_value 初始化
template <typename OtherT>
constexpr member(tag_and_value<Tag, OtherT> tv) : value(std::move(tv.value)) {}
// 默认构造:使用 Init 初始化,可依赖结构体中其他成员
template <typename Self>
constexpr member(Self& self) : value(call_init<T>(self, Init)) {}
// 默认拷贝、移动构造和赋值
constexpr member(member&&) = default;
constexpr member(const member&) = default;
constexpr member& operator=(member&&) = default;
constexpr member& operator=(const member&) = default;
auto operator<=>(const member&) const = default; // 三向比较
};
// ----------------- 元结构体实现层 -----------------
template <typename... Members>
struct meta_struct_impl : Members... {
// 使用参数包初始化所有成员
template <typename Parms>
constexpr meta_struct_impl(Parms p) : Members(std::move(p))... {}
// 默认构造:依次调用每个 member(Self&) 构造
constexpr meta_struct_impl() : Members(*this)... {}
// 默认拷贝、移动构造和赋值
constexpr meta_struct_impl(meta_struct_impl&&) = default;
constexpr meta_struct_impl(const meta_struct_impl&) = default;
constexpr meta_struct_impl& operator=(meta_struct_impl&&) = default;
constexpr meta_struct_impl& operator=(const meta_struct_impl&) = default;
auto operator<=>(const meta_struct_impl&) const = default; // 三向比较
};
// ----------------- 元结构体外层接口 -----------------
template <typename... Members>
struct meta_struct : meta_struct_impl<Members...> {
using super = meta_struct_impl<Members...>;
// 支持按标签初始化
template <typename... TagsAndValues>
constexpr meta_struct(TagsAndValues... tags_and_values)
: super(parms(std::move(tags_and_values)...)) {}
constexpr meta_struct() = default;
constexpr meta_struct(meta_struct&&) = default;
constexpr meta_struct(const meta_struct&) = default;
constexpr meta_struct& operator=(meta_struct&&) = default;
constexpr meta_struct& operator=(const meta_struct&) = default;
auto operator<=>(const meta_struct&) const = default;
};
// ----------------- 元结构体 apply 函数 -----------------
// 遍历结构体成员,执行函数 f
template <typename F, typename... MembersImpl>
constexpr decltype(auto) meta_struct_apply(F&& f, meta_struct_impl<MembersImpl...>& m) {
return std::forward<F>(f)(static_cast<MembersImpl&>(m)...);
}
template <typename F, typename... MembersImpl>
constexpr decltype(auto) meta_struct_apply(F&& f, const meta_struct_impl<MembersImpl...>& m) {
return std::forward<F>(f)(static_cast<const MembersImpl&>(m)...);
}
template <typename F, typename... MembersImpl>
constexpr decltype(auto) meta_struct_apply(F&& f, meta_struct_impl<MembersImpl...>&& m) {
return std::forward<F>(f)(static_cast<MembersImpl&&>(m)...);
}
// 静态版本:在编译期获取成员类型,不需要实例
template <typename MetaStructImpl>
struct apply_static_impl;
template <typename... MembersImpl>
struct apply_static_impl<meta_struct_impl<MembersImpl...>> {
template <typename F>
constexpr static decltype(auto) apply(F&& f) {
return f(static_cast<MembersImpl*>(nullptr)...);
}
};
template <typename MetaStruct, typename F>
auto meta_struct_apply(F&& f) {
return apply_static_impl<typename MetaStruct::super>::apply(std::forward<F>(f));
}
// ----------------- get 函数:通过标签获取成员值 -----------------
template <fixed_string tag, typename T, auto Init>
decltype(auto) get_impl(member<tag, T, Init>& m) { return (m.value); }
template <fixed_string tag, typename T, auto Init>
decltype(auto) get_impl(const member<tag, T, Init>& m) { return (m.value); }
template <fixed_string tag, typename T, auto Init>
decltype(auto) get_impl(member<tag, T, Init>&& m) { return std::move(m.value); }
template <fixed_string tag, typename MetaStruct>
decltype(auto) get(MetaStruct&& s) { return get_impl<tag>(std::forward<MetaStruct>(s)); }
// ----------------- 测试用例 -----------------
#include <iostream>
#include <string>
int main() {
// 定义一个 Person 元结构体
// id 使用默认初始化 0
// score 依赖 id 初始化,值为 id+1
// name 默认初始化为 "John"
using Person = meta_struct<
member<"id", int>,
member<"score", int, [](auto& self) { return get<"id">(self) + 1; }>,
member<"name", std::string, [] { return "John"; }>
>;
// 输出编译期标签
meta_struct_apply<Person>([]<typename... M>(M*...) {
std::cout << "The tags are: ";
((std::cout << M::tag().sv() << " "), ...);
std::cout << "\n";
});
Person p; // 默认构造
// 输出成员值
meta_struct_apply(
[&](const auto&... m) { ((std::cout << m.tag().sv() << ":" << m.value << "\n"), ...); }, p);
}
理解
- 固定字符串
fixed_string用于在编译期表示标签。 member<Tag, T, Init>表示一个成员,支持:- 默认初始化
- 依赖其他成员的初始化(通过
Self&lambda) - 标签值初始化
meta_struct聚合所有成员,支持:- 标签初始化(顺序无关)
- 默认构造(调用每个成员的 Init)
meta_struct_apply可以遍历成员类型或实例
get<Tag>(obj)可以通过标签获取成员值。- 编译期与运行时结合:
- 可以在编译期获取成员类型或标签
- 运行时可以直接访问成员值
#include <algorithm>
#include <cstddef>
#include <optional>
#include <string_view>
#include <type_traits>
// ----------------- 固定长度字符串包装,用作模板非类型参数 -----------------
template <std::size_t N>
struct fixed_string {
// 构造函数:将 C 字符数组拷贝到 data 中
constexpr fixed_string(const char (&foo)[N + 1]) { std::copy_n(foo, N + 1, data); }
// 支持 std::string_view 构造,注意长度必须 <= N
constexpr fixed_string(std::string_view s) {
static_assert(s.size() <= N);
std::copy(s.begin(), s.end(), data);
}
// 返回字符串视图
constexpr std::string_view sv() const { return std::string_view(data); }
// 三向比较,方便固定字符串比较
auto operator<=>(const fixed_string&) const = default;
char data[N + 1] = {}; // 存储字符串内容,末尾 '\0'
};
// 推导向导:允许 const char[N] 自动转换为 fixed_string<N-1>
template <std::size_t N>
fixed_string(const char (&str)[N]) -> fixed_string<N - 1>;
// ----------------- 标签和值组合,用于初始化成员 -----------------
template <fixed_string Tag, typename T>
struct tag_and_value {
T value; // 保存标签对应的值
};
// ----------------- 特殊类型,用于区分无法匹配的转换 -----------------
struct no_conversion {};
// ----------------- 参数包,用于聚合多个 tag_and_value -----------------
template <typename... TagsAndValues>
struct parms : TagsAndValues... {
// 如果尝试将 parms 转换为值失败,返回 no_conversion
constexpr operator no_conversion() const { return no_conversion{}; }
};
// 推导向导
template <typename... TagsAndValues>
parms(TagsAndValues...) -> parms<TagsAndValues...>;
// ----------------- 标签语法糖 -----------------
template <fixed_string Tag>
struct arg_type {
template <typename T>
constexpr auto operator=(T t) const {
return tag_and_value<Tag, T>{std::move(t)}; // 返回 tag_and_value
}
};
template <fixed_string Tag>
inline constexpr auto arg = arg_type<Tag>{}; // 全局常量,方便使用 arg<"id"> = 1
// ----------------- 默认初始化器 -----------------
template <typename T>
struct default_init {
constexpr default_init() = default;
auto operator<=>(const default_init&) const = default;
// 如果类型可默认构造,返回 T{}
constexpr auto operator()() const {
if constexpr (std::is_default_constructible_v<T>) {
return T{};
}
}
};
// ----------------- 支持依赖的初始化函数 -----------------
template <typename T, typename Self, typename F>
auto call_init(Self&, F& f)
requires(requires { { f() } -> std::convertible_to<T>; })
{
return f(); // 调用无参数初始化器
}
template <typename T, typename Self, typename F>
auto call_init(Self& self, F& f)
requires(requires { { f(self) } -> std::convertible_to<T>; })
{
return f(self); // 调用带 self 参数的初始化器
}
template <typename T, typename Self, typename F>
auto call_init(Self& self, F& f)
requires(requires { { f() } -> std::same_as<void>; })
{} // 如果初始化器返回 void,不做操作
// ----------------- 元成员定义 -----------------
template <fixed_string Tag, typename T, auto Init = default_init<T>()>
struct member {
constexpr static auto tag() { return Tag; } // 获取标签
constexpr static auto init() { return Init; } // 获取初始化器
using element_type = T; // 成员类型
T value; // 成员值
// 使用 tag_and_value 初始化成员
template <typename Self, typename OtherT>
constexpr member(Self&, tag_and_value<Tag, OtherT> tv) : value(std::move(tv.value)) {}
// 默认初始化,依赖 Self 结构体
template <typename Self>
constexpr member(Self& self) : value(call_init<T>(self, Init)) {}
// 如果参数为 no_conversion,也使用默认初始化
template <typename Self>
constexpr member(Self& self, no_conversion) : value(call_init<T>(self, Init)) {}
// 如果参数为 std::optional<T>,如果有值使用值,否则调用默认初始化
template <typename Self>
constexpr member(Self& self, tag_and_value<Tag, std::optional<T>> tv_or)
: value(tv_or.value.has_value() ? std::move(*tv_or.value) : call_init<T>(self, Init)) {}
// 默认拷贝、移动构造和赋值
constexpr member(member&&) = default;
constexpr member(const member&) = default;
constexpr member& operator=(member&&) = default;
constexpr member& operator=(const member&) = default;
auto operator<=>(const member&) const = default; // 三向比较
};
// ----------------- 元结构体实现层 -----------------
template <typename... Members>
struct meta_struct_impl : Members... {
// 使用参数包初始化成员
template <typename Parms>
constexpr meta_struct_impl(Parms p) : Members(*this, std::move(p))... {}
// 默认构造:依次调用每个成员的默认初始化
constexpr meta_struct_impl() : Members(*this)... {}
// 默认拷贝、移动构造和赋值
constexpr meta_struct_impl(meta_struct_impl&&) = default;
constexpr meta_struct_impl(const meta_struct_impl&) = default;
constexpr meta_struct_impl& operator=(meta_struct_impl&&) = default;
constexpr meta_struct_impl& operator=(const meta_struct_impl&) = default;
auto operator<=>(const meta_struct_impl&) const = default;
};
// ----------------- 元结构体外层接口 -----------------
template <typename... Members>
struct meta_struct : meta_struct_impl<Members...> {
using super = meta_struct_impl<Members...>;
// 标签初始化构造函数
template <typename... TagsAndValues>
constexpr meta_struct(TagsAndValues... tags_and_values)
: super(parms(std::move(tags_and_values)...)) {}
constexpr meta_struct() = default;
constexpr meta_struct(meta_struct&&) = default;
constexpr meta_struct(const meta_struct&) = default;
constexpr meta_struct& operator=(meta_struct&&) = default;
constexpr meta_struct& operator=(const meta_struct&) = default;
auto operator<=>(const meta_struct&) const = default;
};
// ----------------- 遍历成员 apply -----------------
template <typename F, typename... MembersImpl>
constexpr decltype(auto) meta_struct_apply(F&& f, meta_struct_impl<MembersImpl...>& m) {
return std::forward<F>(f)(static_cast<MembersImpl&>(m)...);
}
template <typename F, typename... MembersImpl>
constexpr decltype(auto) meta_struct_apply(F&& f, const meta_struct_impl<MembersImpl...>& m) {
return std::forward<F>(f)(static_cast<const MembersImpl&>(m)...);
}
template <typename F, typename... MembersImpl>
constexpr decltype(auto) meta_struct_apply(F&& f, meta_struct_impl<MembersImpl...>&& m) {
return std::forward<F>(f)(static_cast<MembersImpl&&>(m)...);
}
// 静态版本:在编译期获取成员类型,不需要实例
template <typename MetaStructImpl>
struct apply_static_impl;
template <typename... MembersImpl>
struct apply_static_impl<meta_struct_impl<MembersImpl...>> {
template <typename F>
constexpr static decltype(auto) apply(F&& f) {
return f(static_cast<MembersImpl*>(nullptr)...);
}
};
template <typename MetaStruct, typename F>
auto meta_struct_apply(F&& f) {
return apply_static_impl<typename MetaStruct::super>::apply(std::forward<F>(f));
}
// ----------------- get 函数:通过标签获取成员值 -----------------
template <fixed_string tag, typename T, auto Init>
decltype(auto) get_impl(member<tag, T, Init>& m) { return (m.value); }
template <fixed_string tag, typename T, auto Init>
decltype(auto) get_impl(const member<tag, T, Init>& m) { return (m.value); }
template <fixed_string tag, typename T, auto Init>
decltype(auto) get_impl(member<tag, T, Init>&& m) { return std::move(m.value); }
template <fixed_string tag, typename MetaStruct>
decltype(auto) get(MetaStruct&& s) { return get_impl<tag>(std::forward<MetaStruct>(s)); }
// ----------------- 打印成员值的辅助函数 -----------------
#include <iostream>
#include <string>
template <typename MetaStruct>
void print(std::ostream& os, const MetaStruct& ms) {
meta_struct_apply(
[&](const auto&... m) {
auto print_item = [&](auto& m) { std::cout << m.tag().sv() << ":" << m.value << "\n"; };
(print_item(m), ...);
},
ms);
};
// ----------------- 测试用例 -----------------
int main() {
// 定义 Person 元结构体
using Person = meta_struct<
member<"id", int>,
member<"score", int, [](auto& self) { return get<"id">(self) + 1; }>, // score 依赖 id
member<"name", std::string, [] { return "John"; }>
>;
// 输出标签名(编译期)
meta_struct_apply<Person>([]<typename... M>(M*...) {
std::cout << "The tags are: ";
auto print_tag = [](auto t) { std::cout << t.sv() << " "; };
(print_tag(M::tag()), ...);
std::cout << "\n";
});
// 构造 Person,指定 id
Person p{arg<"id"> = 2};
std::cout << get<"id">(p) << " " << get<"name">(p) << " " << get<"score">(p) << "\n";
// 构造 Person,score 使用 optional 为空,触发默认初始化
Person p2{arg<"id"> = 2, arg<"score"> = std::optional<int>()};
print(std::cout, p2);
// 构造 Person,score 使用 optional 指定值
Person p3{arg<"id"> = 2, arg<"score"> = std::optional<int>(500)};
print(std::cout, p3);
}
理解
- fixed_string:编译期字符串,作为模板非类型参数(标签)。
- tag_and_value:标签 + 值组合,支持初始化成员。
- parms:参数包,可聚合多个 tag_and_value,并可安全转换为
no_conversion。 - member<Tag, T, Init>:
- 支持标签值初始化
- 支持默认初始化
- 支持依赖其他成员初始化(通过 lambda)
- 支持 optional 值覆盖默认值
- meta_struct:聚合多个成员,支持标签初始化和默认初始化。
- meta_struct_apply:遍历结构体成员,执行给定函数。
- get(obj):根据标签获取成员值。
- 示例:
Person p{arg<"id"> = 2};→ score 自动依赖 id 初始化Person p2{arg<"score"> = std::optional<int>()};→ 如果 optional 无值,使用默认初始化Person p3{arg<"score"> = std::optional<int>(500)};→ 使用 optional 的值覆盖默认初始化
核心思想是用编译期标签(fixed_string)和模板元结构体实现类似“命名参数”和“依赖初始化”的功能。我把它拆解成几个关键点来讲解。
1⃣ fixed_string —— 编译期字符串
template <std::size_t N>
struct fixed_string {
char data[N+1]{};
constexpr fixed_string(const char (&foo)[N+1]) { std::copy_n(foo, N+1, data); }
constexpr fixed_string(std::string_view s) { std::copy(s.begin(), s.end(), data); }
constexpr std::string_view sv() const { return std::string_view(data); }
auto operator<=>(const fixed_string&) const = default;
};
- 作用:用于模板非类型参数(NTTP),实现编译期的标签。
- 例子:
fixed_string<2> t("id");,或者通过模板推导fixed_string fs = "id";。 - 特性:支持三向比较
<=>,方便作为模板参数比较。
2⃣ tag_and_value 和 arg_type —— 标签和值的组合
template <fixed_string Tag, typename T>
struct tag_and_value { T value; };
template <fixed_string Tag>
struct arg_type {
template <typename T>
constexpr auto operator=(T t) const { return tag_and_value<Tag,T>{std::move(t)}; }
};
template <fixed_string Tag>
inline constexpr auto arg = arg_type<Tag>{};
- 作用:
arg<"id"> = 2会生成tag_and_value<"id", int>{2}。- 类似“命名参数”,可以在构造
meta_struct时指定成员的值。
- 方便初始化:
- 支持 optional 覆盖默认值。
- 支持 lambda 依赖其他成员。
3⃣ default_init 和 call_init —— 默认/依赖初始化
template <typename T>
struct default_init {
constexpr auto operator()() const { if constexpr (std::is_default_constructible_v<T>) return T{}; }
};
template <typename T, typename Self, typename F>
auto call_init(Self& self, F& f) { ... }
default_init<T>:默认构造值,如果类型可默认构造。call_init:- 如果初始化器是无参 lambda,调用
f()。 - 如果初始化器依赖其他成员,调用
f(self)。 - 如果初始化器返回 void,则不做操作。
例子:
- 如果初始化器是无参 lambda,调用
member<"score", int, [](auto& self){ return get<"id">(self)+1; }>
score的值依赖同一个meta_struct的id成员。
4⃣ member —— 单个成员模板
template <fixed_string Tag, typename T, auto Init = default_init<T>()>
struct member {
T value;
template <typename Self, typename OtherT>
member(Self&, tag_and_value<Tag, OtherT> tv) : value(tv.value) {}
template <typename Self>
member(Self& self) : value(call_init<T>(self, Init)) {}
template <typename Self>
member(Self& self, tag_and_value<Tag,std::optional<T>> tv_or)
: value(tv_or.value.has_value() ? *tv_or.value : call_init<T>(self, Init)) {}
};
- 功能:
- 可以通过
tag_and_value初始化。 - 如果未指定值,使用默认初始化器。
- 支持 optional 覆盖默认值。
- 可以通过
- 特点:构造时可以访问
Self,实现依赖初始化。
5⃣ meta_struct —— 元结构体
template <typename... Members>
struct meta_struct : meta_struct_impl<Members...> {
template <typename... TagsAndValues>
meta_struct(TagsAndValues... tags_and_values) : super(parms(tags_and_values...)) {}
};
- 核心:继承了
meta_struct_impl<Members...>,聚合多个成员。 - 构造方式:
- 可以通过标签初始化成员。
- 未指定成员使用默认初始化。
- 可用方法:
get<"id">(p)获取成员值。meta_struct_apply遍历成员执行操作。
6⃣ meta_struct_apply —— 遍历结构体成员
template <typename F, typename... MembersImpl>
decltype(auto) meta_struct_apply(F&& f, meta_struct_impl<MembersImpl...>& m) {
return f(static_cast<MembersImpl&>(m)...);
}
- 作用:把结构体的每个成员作为参数传给函数
f。 - 用途:
- 遍历打印成员。
- 可以做序列化、依赖计算等。
7⃣ get —— 根据标签获取值
template <fixed_string tag, typename MetaStruct>
decltype(auto) get(MetaStruct&& s) { return get_impl<tag>(std::forward<MetaStruct>(s)); }
- 直接获取成员的值,不需要手动写
p.score。 - 支持常量引用和右值引用。
8⃣ 使用示例
using Person = meta_struct<
member<"id", int>,
member<"score", int, [](auto& self){ return get<"id">(self)+1; }>,
member<"name", std::string, []{ return "John"; }>
>;
Person p{arg<"id"> = 2}; // id=2, score=3, name="John"
Person p2{arg<"score"> = std::optional<int>()}; // score 空时用默认初始化
Person p3{arg<"score"> = std::optional<int>(500)}; // score=500
- 特点:
score可以依赖id初始化。- 支持 optional 优先覆盖。
- 标签初始化方式清晰,类似命名参数。
总结
- 模板元结构体 + 固定标签实现了类似命名参数和依赖初始化。
- 优先级:
- 如果提供
tag_and_value且是非 optional → 使用它。 - 如果是 optional 且有值 → 使用值。
- 否则 → 调用默认初始化器。
- 如果提供
- 灵活性:
- 可用于序列化、配置管理、数据绑定。
- 所有成员在编译期可遍历。
- 优点:
- 无运行时字符串。
- 类型安全,避免手动索引。
- 支持依赖计算。
#include <algorithm>
#include <cstddef>
#include <optional>
#include <string_view>
#include <type_traits>
// ==========================
// 编译期字符串 fixed_string
// ==========================
template <std::size_t N>
struct fixed_string {
char data[N + 1] = {}; // 用于存储字符串内容,末尾自动加 '\0'
// 从字符数组构造
constexpr fixed_string(const char (&foo)[N + 1]) {
std::copy_n(foo, N + 1, data);
}
// 从 string_view 构造
constexpr fixed_string(std::string_view s) {
static_assert(s.size() <= N);
std::copy(s.begin(), s.end(), data);
}
// 返回 string_view 方便访问
constexpr std::string_view sv() const { return std::string_view(data); }
auto operator<=>(const fixed_string&) const = default; // 三向比较
};
// 自动模板参数推导
template <std::size_t N>
fixed_string(const char (&str)[N]) -> fixed_string<N - 1>;
// ==========================
// 标签和值 tag_and_value
// ==========================
template <fixed_string Tag, typename T>
struct tag_and_value {
T value; // 存储对应值
};
// 用于表示未提供值的情况
struct no_conversion {};
// ==========================
// 参数组合 parms
// ==========================
template <typename... TagsAndValues>
struct parms : TagsAndValues... {
// 可以隐式转换为 no_conversion,表示没有提供参数
constexpr operator no_conversion() const { return no_conversion{}; }
};
// 构造参数模板推导
template <typename... TagsAndValues>
parms(TagsAndValues...) -> parms<TagsAndValues...>;
// ==========================
// 命名参数语法 arg
// ==========================
template <fixed_string Tag>
struct arg_type {
template <typename T>
constexpr auto operator=(T t) const {
return tag_and_value<Tag, T>{std::move(t)};
}
};
template <fixed_string Tag>
inline constexpr auto arg = arg_type<Tag>{}; // 全局变量,方便使用 arg<"id"> = 2;
// ==========================
// 默认初始化 default_init
// ==========================
template <typename T>
struct default_init {
constexpr default_init() = default;
auto operator<=>(const default_init&) const = default;
// 默认调用类型的默认构造函数
constexpr auto operator()() const {
if constexpr (std::is_default_constructible_v<T>) {
return T{};
}
}
};
// ==========================
// 调用初始化器 call_init
// ==========================
template <typename T, typename Self, typename F>
auto call_init(Self&, F& f)
requires(requires { { f() } -> std::convertible_to<T>; }) {
return f(); // 无参 lambda
}
template <typename T, typename Self, typename F>
auto call_init(Self& self, F& f)
requires(requires { { f(self) } -> std::convertible_to<T>; }) {
return f(self); // 依赖 self 的 lambda
}
template <typename T, typename Self, typename F>
auto call_init(Self& self, F& f)
requires(requires { { f() } -> std::same_as<void>; }) {
static_assert(!std::is_same_v<decltype(f()), void>, "Required argument not specified");
}
// 用于标记必须提供的参数
inline constexpr auto required = [] {};
// ==========================
// 单个成员 member
// ==========================
template <fixed_string Tag, typename T, auto Init = default_init<T>()>
struct member {
using element_type = T;
T value;
constexpr static auto tag() { return Tag; }
constexpr static auto init() { return Init; }
// 用 tag_and_value 初始化
template <typename Self, typename OtherT>
constexpr member(Self&, tag_and_value<Tag, OtherT> tv) : value(std::move(tv.value)) {}
// 默认初始化
template <typename Self>
constexpr member(Self& self) : value(call_init<T>(self, Init)) {}
// no_conversion 表示未提供参数
template <typename Self>
constexpr member(Self& self, no_conversion) : value(call_init<T>(self, Init)) {}
// optional 覆盖初始化,非引用类型才允许
template <typename Self>
constexpr member(Self& self,
tag_and_value<Tag, std::optional<std::remove_reference_t<T>>> tv_or)
requires(!std::is_reference_v<T>)
: value(tv_or.value.has_value() ? std::move(*tv_or.value) : call_init<T>(self, Init)) {}
// 默认构造/拷贝/移动
constexpr member(member&&) = default;
constexpr member(const member&) = default;
constexpr member& operator=(member&&) = default;
constexpr member& operator=(const member&) = default;
auto operator<=>(const member&) const = default; // 三向比较
};
// ==========================
// meta_struct_impl: 成员聚合
// ==========================
template <typename... Members>
struct meta_struct_impl : Members... {
template <typename Parms>
constexpr meta_struct_impl(Parms p) : Members(*this, std::move(p))... {}
constexpr meta_struct_impl() : Members(*this)... {}
constexpr meta_struct_impl(meta_struct_impl&&) = default;
constexpr meta_struct_impl(const meta_struct_impl&) = default;
constexpr meta_struct_impl& operator=(meta_struct_impl&&) = default;
constexpr meta_struct_impl& operator=(const meta_struct_impl&) = default;
auto operator<=>(const meta_struct_impl&) const = default;
};
// ==========================
// meta_struct: 用户可见结构体
// ==========================
template <typename... Members>
struct meta_struct : meta_struct_impl<Members...> {
using super = meta_struct_impl<Members...>;
template <typename... TagsAndValues>
constexpr meta_struct(TagsAndValues... tags_and_values)
: super(parms(std::move(tags_and_values)...)) {}
constexpr meta_struct() = default;
constexpr meta_struct(meta_struct&&) = default;
constexpr meta_struct(const meta_struct&) = default;
constexpr meta_struct& operator=(meta_struct&&) = default;
constexpr meta_struct& operator=(const meta_struct&) = default;
auto operator<=>(const meta_struct&) const = default;
};
// ==========================
// 遍历成员 meta_struct_apply
// ==========================
template <typename F, typename... MembersImpl>
constexpr decltype(auto) meta_struct_apply(F&& f, meta_struct_impl<MembersImpl...>& m) {
return std::forward<F>(f)(static_cast<MembersImpl&>(m)...);
}
template <typename F, typename... MembersImpl>
constexpr decltype(auto) meta_struct_apply(F&& f, const meta_struct_impl<MembersImpl...>& m) {
return std::forward<F>(f)(static_cast<const MembersImpl&>(m)...);
}
template <typename F, typename... MembersImpl>
constexpr decltype(auto) meta_struct_apply(F&& f, meta_struct_impl<MembersImpl...>&& m) {
return std::forward<F>(f)(static_cast<MembersImpl&&>(m)...);
}
// 静态遍历 apply_static_impl
template <typename MetaStructImpl>
struct apply_static_impl;
template <typename... MembersImpl>
struct apply_static_impl<meta_struct_impl<MembersImpl...>> {
template <typename F>
constexpr static decltype(auto) apply(F&& f) {
return f(static_cast<MembersImpl*>(nullptr)...);
}
};
template <typename MetaStruct, typename F>
auto meta_struct_apply(F&& f) {
return apply_static_impl<typename MetaStruct::super>::apply(std::forward<F>(f));
}
// ==========================
// 获取成员 get
// ==========================
template <fixed_string tag, typename T, auto Init>
decltype(auto) get_impl(member<tag, T, Init>& m) { return (m.value); }
template <fixed_string tag, typename T, auto Init>
decltype(auto) get_impl(const member<tag, T, Init>& m) { return (m.value); }
template <fixed_string tag, typename T, auto Init>
decltype(auto) get_impl(member<tag, T, Init>&& m) { return std::move(m.value); }
template <fixed_string tag, typename MetaStruct>
decltype(auto) get(MetaStruct&& s) { return get_impl<tag>(std::forward<MetaStruct>(s)); }
// ==========================
// 打印 meta_struct
// ==========================
#include <iostream>
#include <string>
template <typename MetaStruct>
void print(std::ostream& os, const MetaStruct& ms) {
meta_struct_apply(
[&](const auto&... m) {
auto print_item = [&](auto& m) { std::cout << m.tag().sv() << ":" << m.value << "\n"; };
(print_item(m), ...); // 展开打印所有成员
},
ms);
}
// ==========================
// 示例: substr_args 和 substr 函数
// ==========================
using substr_args = meta_struct<
member<"str", const std::string&, required>, // 必须提供 str
member<"offset", std::size_t, [] { return 0; }>, // 默认 offset = 0
member<"count", std::size_t,
[](auto& self) { return get<"str">(self).size() - get<"offset">(self); }> // 默认 count = str.size() - offset
>;
auto substr(substr_args args) {
return get<"str">(args).substr(get<"offset">(args), get<"count">(args));
}
// ==========================
// main 示例
// ==========================
int main() {
// 定义 Person 元结构体
using Person = meta_struct<
member<"id", int, required>, // 必须提供 id
member<"name", std::string, required>, // 必须提供 name
member<"score", int, [](auto& self){ return get<"id">(self) + 1; }> // 默认 score = id+1
>;
// 遍历打印标签
meta_struct_apply<Person>([]<typename... M>(M*...) {
std::cout << "The tags are: ";
auto print_tag = [](auto t) { std::cout << t.sv() << " "; };
(print_tag(M::tag()), ...);
std::cout << "\n";
});
// 构造 Person
Person p{arg<"id"> = 2, arg<"name"> = "John"};
std::cout << get<"id">(p) << " " << get<"name">(p) << " " << get<"score">(p) << "\n";
// 构造 Person,可用 optional 覆盖默认值
Person p2{arg<"name"> = "JRB", arg<"id"> = 2, arg<"score"> = std::optional<int>()};
print(std::cout, p2);
// 字符串截取示例
std::string s = "Hello World";
auto pos = s.find(' ');
auto all = substr({arg<"str"> = std::ref(s)});
auto first = substr({arg<"str"> = std::ref(s), arg<"count"> = pos});
auto second = substr({arg<"str"> = std::ref(s), arg<"offset"> = pos + 1});
std::cout << all << "\n" << first << "\n" << second << "\n";
}
注解总结
fixed_string→ 编译期标签,用于模板参数。arg<"tag"> = value→ 类似命名参数初始化。required→ 标记必须提供的参数。member→ 单个成员支持默认值、依赖初始化、optional 覆盖。meta_struct→ 聚合多个成员,提供 get/apply 功能。substr_args/substr→ 演示如何用 meta_struct 模拟命名参数函数。
详细梳理这段代码的核心思想、运行机制和各个部分的逻辑。
1⃣ fixed_string — 编译期字符串标签
template <std::size_t N>
struct fixed_string { ... };
- 用于在编译期存储字符串,使其可以作为模板参数使用。
- 支持从
char[]或std::string_view构造。 - 提供
sv()返回std::string_view方便运行时访问。 - 支持
<=>三向比较。
作用:作为成员的标签,保证类型安全的命名参数系统。
2⃣ tag_and_value 与 arg
template <fixed_string Tag, typename T>
struct tag_and_value { T value; };
template <fixed_string Tag>
inline constexpr auto arg = arg_type<Tag>{};
arg<"id"> = 2产生tag_and_value<"id", int>。- 实现类似命名参数的写法。
作用:构造meta_struct时提供清晰的成员初始化。
3⃣ required 与 default_init
inline constexpr auto required = [] {};
template <typename T>
struct default_init { ... };
required→ 标记必须提供的参数,如果缺失会在编译时报错。default_init<T>→ 默认构造值,如果成员可默认构造,则自动初始化。
作用:实现参数的可选/必填控制。
4⃣ call_init — 初始化函数调用机制
template <typename T, typename Self, typename F>
auto call_init(Self&, F& f) { ... }
- 支持三种初始化方式:
f()返回类型可转换到Tf(self)返回类型可转换到T- 返回
void→ 报错,表示必填参数未提供
作用:支持依赖其他成员的初始化(延迟初始化)。
5⃣ member — 单个成员
template <fixed_string Tag, typename T, auto Init = default_init<T>()>
struct member { ... };
- 核心成员
value - 支持三种构造方式:
tag_and_value初始化- 默认初始化(可依赖
self) optional覆盖值
- 提供
tag()返回标签,init()返回初始化器 - 支持
<=>比较
作用:单个成员的封装,支持依赖和可选参数。
6⃣ meta_struct — 成员聚合
template <typename... Members>
struct meta_struct : meta_struct_impl<Members...> { ... };
- 继承多个
member,实现多重继承聚合 - 支持:
- 命名参数初始化
- 默认值初始化
- optional 覆盖
- 提供
get<"tag">()获取成员值 - 提供
meta_struct_apply遍历成员
作用:实现类似 Python dataclass 的功能,但在 C++ 中支持编译期安全和依赖初始化。
7⃣ meta_struct_apply — 遍历成员
template <typename F, typename... MembersImpl>
constexpr decltype(auto) meta_struct_apply(F&& f, meta_struct_impl<MembersImpl...>& m)
- 将 lambda 应用于所有成员
- 可用于打印、操作、生成依赖
apply_static_impl提供静态访问(编译期获取标签类型)
8⃣ get — 获取成员
template <fixed_string tag, typename MetaStruct>
decltype(auto) get(MetaStruct&& s)
- 对应
member的value - 支持左值、右值、const
9⃣ 示例:Person 与 substr
using Person = meta_struct<
member<"id", int, required>,
member<"name", std::string, required>,
member<"score", int, [](auto& self) { return get<"id">(self) + 1; }>
>;
id和name必须提供score默认等于id + 1→ 演示依赖初始化- 初始化顺序:
- id
- name
- score (依赖 id)
using substr_args = meta_struct<
member<"str", const std::string&, required>,
member<"offset", std::size_t, [] { return 0; }>,
member<"count", std::size_t, [](auto& self) { return get<"str">(self).size() - get<"offset">(self); }>
>;
- 演示命名参数函数:
substr({arg<"str"> = s, arg<"offset"> = 2})
核心思想
- 使用 固定字符串模板 做编译期标签
member封装每个成员,支持依赖、默认值、optional 覆盖meta_struct聚合多个memberarg<"tag"> = value提供命名参数初始化meta_struct_apply遍历所有成员,支持打印、计算、依赖初始化
10⃣ 输出示例
The tags are: id name score
2 John 3
id:2
name:JRB
score:3
Hello World
Hello
World
- 展示了:
- 标签顺序
- 成员初始化和默认值
substr函数的命名参数调用
逐步解释每个部分的作用和机制。
#include <algorithm>
#include <cstddef>
#include <optional>
#include <string_view>
#include <type_traits>
// ==========================
// 编译期字符串标签
// ==========================
template <std::size_t N>
struct fixed_string {
// 从字面量数组构造
constexpr fixed_string(const char (&foo)[N + 1]) { std::copy_n(foo, N + 1, data); }
// 从 std::string_view 构造
constexpr fixed_string(std::string_view s) {
static_assert(s.size() <= N);
std::copy(s.begin(), s.end(), data);
}
// 返回 std::string_view 方便运行时访问
constexpr std::string_view sv() const { return std::string_view(data); }
auto operator<=>(const fixed_string&) const = default;
char data[N + 1] = {}; // 存储字符串数据
};
// 类模板参数推导:char数组 -> fixed_string
template <std::size_t N>
fixed_string(const char (&str)[N]) -> fixed_string<N - 1>;
// ==========================
// 标签-值对,用于命名参数
// ==========================
template <fixed_string Tag, typename T>
struct tag_and_value {
T value;
};
// forward declaration
template <typename... Members>
struct meta_struct;
template <typename... Members>
meta_struct(Members...) -> meta_struct<Members...>;
// 空的 meta_struct 特化
template <>
struct meta_struct<> {};
// ==========================
// 无转换标记,用于初始化缺失参数
// ==========================
struct no_conversion {};
// ==========================
// 封装参数包,用于构造 meta_struct
// ==========================
template <typename... TagsAndValues>
struct parms : TagsAndValues... {
constexpr operator no_conversion() const { return no_conversion{}; }
};
template <typename... TagsAndValues>
parms(TagsAndValues...) -> parms<TagsAndValues...>;
// ==========================
// 默认初始化器
// ==========================
template <typename T>
struct default_init {
constexpr default_init() = default;
auto operator<=>(const default_init&) const = default;
constexpr auto operator()() const {
if constexpr (std::is_default_constructible_v<T>) {
return T{}; // 如果可默认构造,则返回默认值
}
}
};
// ==========================
// 初始化调用机制
// 支持 f() / f(self) / required 检查
// ==========================
template <typename T, typename Self, typename F>
constexpr auto call_init(Self&, F& f)
requires(requires { { f() } -> std::convertible_to<T>; }) {
return f();
}
template <typename T, typename Self, typename F>
constexpr auto call_init(Self& self, F& f)
requires(requires { { f(self) } -> std::convertible_to<T>; }) {
return f(self);
}
template <typename T, typename Self, typename F>
constexpr auto call_init(Self& self, F& f)
requires(requires { { f() } -> std::same_as<void>; }) {
static_assert(!std::is_same_v<decltype(f()), void>, "Required argument not specified");
}
// 必须提供的参数标记
inline constexpr auto required = [] {};
// ==========================
// 单个成员封装
// ==========================
template <fixed_string Tag, typename T, auto Init = default_init<T>(), meta_struct Attributes = {}>
struct member {
constexpr static auto tag() { return Tag; }
constexpr static auto init() { return Init; }
constexpr static auto attributes() { return Attributes; }
using element_type = T;
T value;
// 通过 tag_and_value 初始化
template <typename Self, typename OtherT>
constexpr member(Self&, tag_and_value<Tag, OtherT> tv) : value(std::move(tv.value)) {}
// 通过默认值 / 初始化器初始化
template <typename Self>
constexpr member(Self& self, no_conversion)
: value(call_init<T>(self, Init)) {}
// 支持 optional 覆盖
template <typename Self>
constexpr member(Self& self,
tag_and_value<Tag, std::optional<std::remove_reference_t<T>>> tv_or)
requires(!std::is_reference_v<T>)
: value(tv_or.value.has_value() ? std::move(*tv_or.value) : call_init<T>(self, Init)) {}
// 支持从其他 member 拷贝 / 移动初始化
template <typename Self, typename OtherT, auto OtherInit, auto OtherAttributes>
requires(std::is_convertible_v<OtherT, T>)
constexpr member(Self&, const member<Tag, OtherT, OtherInit, OtherAttributes>& other)
: value(other.value) {}
template <typename Self, typename OtherT, auto OtherInit, auto OtherAttributes>
requires(std::is_convertible_v<OtherT, T>)
constexpr member(Self&, member<Tag, OtherT, OtherInit, OtherAttributes>&& other)
: value(std::move(other.value)) {}
// 支持赋值操作符
template <typename OtherT, auto OtherInit, auto OtherAttributes>
requires(std::is_convertible_v<OtherT, T>)
constexpr member& operator=(const member<Tag, OtherT, OtherInit, OtherAttributes>& other) {
value = other.value;
return *this;
}
template <typename OtherT, auto OtherInit, auto OtherAttributes>
requires(std::is_convertible_v<OtherT, T>)
constexpr member& operator=(member<Tag, OtherT, OtherInit, OtherAttributes>&& other) {
value = std::move(other.value);
return *this;
}
// 默认构造/拷贝/移动
constexpr member(member&&) = default;
constexpr member(const member&) = default;
constexpr member& operator=(member&&) = default;
constexpr member& operator=(const member&) = default;
auto operator<=>(const member&) const = default;
};
// ==========================
// meta_struct 实现
// ==========================
template <typename... Members>
struct meta_struct_impl : Members... {
template <typename... Args>
constexpr meta_struct_impl(parms<Args...> p) : Members(*this, std::move(p))... {}
constexpr meta_struct_impl() : Members(*this, no_conversion{})... {}
// 拷贝/移动构造
constexpr meta_struct_impl(meta_struct_impl&&) = default;
constexpr meta_struct_impl(const meta_struct_impl&) = default;
constexpr meta_struct_impl& operator=(meta_struct_impl&&) = default;
constexpr meta_struct_impl& operator=(const meta_struct_impl&) = default;
// 从其他 meta_struct 构造 / 赋值
template <typename... OtherMembers>
constexpr meta_struct_impl(meta_struct_impl<OtherMembers...>&& other)
: Members(*this, std::move(other))... {}
template <typename... OtherMembers>
constexpr meta_struct_impl(const meta_struct_impl<OtherMembers...>& other)
: Members(*this, other)... {}
template <typename... OtherMembers>
constexpr meta_struct_impl& operator=(meta_struct_impl<OtherMembers...>&& other) {
((static_cast<Members&>(*this) = std::move(other)), ...);
return *this;
}
template <typename... OtherMembers>
constexpr meta_struct_impl& operator=(const meta_struct_impl<OtherMembers...>& other) {
((static_cast<Members&>(*this) = other), ...);
return *this;
}
constexpr operator no_conversion() const { return no_conversion{}; }
auto operator<=>(const meta_struct_impl&) const = default;
};
// ==========================
// meta_struct 封装
// ==========================
template <typename... Members>
struct meta_struct : meta_struct_impl<Members...> {
using super = meta_struct_impl<Members...>;
template <typename... TagsAndValues>
constexpr meta_struct(TagsAndValues... tags_and_values)
: super(parms(std::move(tags_and_values)...)) {}
constexpr meta_struct() = default;
constexpr meta_struct(meta_struct&&) = default;
constexpr meta_struct(const meta_struct&) = default;
constexpr meta_struct& operator=(meta_struct&&) = default;
constexpr meta_struct& operator=(const meta_struct&) = default;
template <typename... OtherMembers>
constexpr meta_struct(meta_struct<OtherMembers...>&& other) : super(std::move(other)) {}
template <typename... OtherMembers>
constexpr meta_struct(const meta_struct<OtherMembers...>& other) : super(other) {}
template <typename... OtherMembers>
constexpr meta_struct& operator=(meta_struct<OtherMembers...>&& other) {
static_cast<super&>(*this) = std::move(other);
return *this;
}
template <typename... OtherMembers>
constexpr meta_struct& operator=(const meta_struct<OtherMembers...>& other) {
static_cast<super&>(*this) = other;
return *this;
}
auto operator<=>(const meta_struct&) const = default;
};
// ==========================
// 命名参数语法 sugar
// ==========================
template <fixed_string Tag>
struct arg_type {
template <typename T>
constexpr auto operator=(T t) const {
return member<Tag, T>(*this, tag_and_value<Tag, T>(std::move(t)));
}
};
template <fixed_string Tag>
inline constexpr auto arg = arg_type<Tag>{};
// ==========================
// 遍历成员 lambda 应用
// ==========================
template <typename F, typename... MembersImpl>
constexpr decltype(auto) meta_struct_apply(F&& f, meta_struct_impl<MembersImpl...>& m) {
return std::forward<F>(f)(static_cast<MembersImpl&>(m)...);
}
template <typename F, typename... MembersImpl>
constexpr decltype(auto) meta_struct_apply(F&& f, const meta_struct_impl<MembersImpl...>& m) {
return std::forward<F>(f)(static_cast<const MembersImpl&>(m)...);
}
template <typename F, typename... MembersImpl>
constexpr decltype(auto) meta_struct_apply(F&& f, meta_struct_impl<MembersImpl...>&& m) {
return std::forward<F>(f)(static_cast<MembersImpl&&>(m)...);
}
// ==========================
// 静态访问成员类型
// ==========================
template <typename MetaStructImpl>
struct apply_static_impl;
template <typename... MembersImpl>
struct apply_static_impl<meta_struct_impl<MembersImpl...>> {
template <typename F>
constexpr static decltype(auto) apply(F&& f) {
return f(static_cast<MembersImpl*>(nullptr)...);
}
};
template <typename MetaStruct, typename F>
constexpr auto meta_struct_apply(F&& f) {
return apply_static_impl<typename MetaStruct::super>::apply(std::forward<F>(f));
}
// ==========================
// 获取成员值
// ==========================
template <fixed_string tag, typename T, auto Init, auto Attributes>
constexpr decltype(auto) get_impl(member<tag, T, Init, Attributes>& m) { return (m.value); }
template <fixed_string tag, typename T, auto Init, auto Attributes>
constexpr decltype(auto) get_impl(const member<tag, T, Init, Attributes>& m) { return (m.value); }
template <fixed_string tag, typename T, auto Init, auto Attributes>
constexpr decltype(auto) get_impl(member<tag, T, Init, Attributes>&& m) { return std::move(m.value); }
template <fixed_string tag, typename MetaStruct>
constexpr decltype(auto) get(MetaStruct&& s) { return get_impl<tag>(std::forward<MetaStruct>(s)); }
// ==========================
// 打印 meta_struct
// ==========================
#include <iostream>
#include <string>
template <typename MetaStruct>
void print(std::ostream& os, const MetaStruct& ms) {
meta_struct_apply(
[&](const auto&... m) {
auto print_item = [&](auto& m) { std::cout << m.tag().sv() << ":" << m.value << "\n"; };
(print_item(m), ...);
},
ms);
}
// ==========================
// 示例:Name 和 Id 参数结构
// ==========================
using NameAndIdArgs = meta_struct<
member<"name", std::string_view>,
member<"id", const int&>
>;
void print_name_id(NameAndIdArgs args) {
std::cout << "Name is " << get<"name">(args) << " and id is " << get<"id">(args) << "\n";
}
// ==========================
// 示例:Person
// ==========================
enum class encoding : int { fixed = 0, variable = 1 };
template <typename P>
void display_person(const P& p) {
std::cout << "The person has an id of " << p.id
<< " and name " << p.name
<< " and scored " << p.score << "\n";
}
// meta_struct 版本的 person
using person_ref = meta_struct<
member<"name", std::string_view, required>,
member<"id", const int&, required>,
member<"score", const int&, required>
>;
void display_person_meta(person_ref p) {
std::cout << "The person has an id of " << get<"id">(p)
<< " and name " << get<"name">(p)
<< " and scored " << get<"score">(p) << "\n";
}
// ==========================
// 普通结构体
// ==========================
struct MyPerson {
std::string name;
int id = 0;
int score = 0;
};
struct YourPerson {
int id = 0;
int score = 0;
std::string name;
};
// meta_struct 对应版本
using MyPersonMeta = meta_struct<
member<"id", int>,
member<"name", std::string>,
member<"score", int>
>;
using YourPersonMeta = meta_struct<
member<"id", int>,
member<"score", int>,
member<"name", std::string>
>;
// ==========================
// main 测试
// ==========================
int main() {
MyPerson p1;
YourPerson p2;
MyPersonMeta pm1;
YourPersonMeta pm2;
display_person(p1);
display_person(p2);
display_person_meta(pm1);
display_person_meta(pm2);
}
总结
- fixed_string → 编译期标签
- member → 封装单个成员,可依赖初始化、optional 覆盖
- meta_struct → 聚合多个成员,实现类似 Python dataclass / struct-of-named-fields 的功能
- arg<“tag”> = value → 命名参数构造
- meta_struct_apply → 遍历成员,用于打印、依赖计算等
1⃣ fixed_string:编译期字符串类型
template <std::size_t N>
struct fixed_string {
char data[N + 1] = {};
constexpr fixed_string(const char (&foo)[N + 1]) {
std::copy_n(foo, N + 1, data);
}
constexpr fixed_string(std::string_view s) {
static_assert(s.size() <= N);
std::copy(s.begin(), s.end(), data);
}
constexpr std::string_view sv() const { return std::string_view(data); }
auto operator<=>(const fixed_string&) const = default;
};
作用:
- 用于在编译期表示固定长度的字符串,比如
"id"、"name"。 - 可以用作模板参数(C++20允许类类型作为非类型模板参数)。
- 提供
sv()返回std::string_view,方便打印或比较。
2⃣ tag_and_value:标签与值的组合
template <fixed_string Tag, typename T>
struct tag_and_value {
T value;
};
作用:
- 用于将某个标签(如
"id")和对应的值绑定,用于初始化member。
3⃣ member:元结构体的成员
template <fixed_string Tag, typename T, auto Init = default_init<T>(), meta_struct Attributes = {}>
struct member {
T value;
static auto tag() { return Tag; }
static auto init() { return Init; }
static auto attributes() { return Attributes; }
...
};
作用:
- 每个
member表示一个字段(比如id、name)。 - 可指定默认值
Init或required。 - 可以从
tag_and_value或另一个member初始化。 - 支持拷贝、移动和比较操作。
4⃣ meta_struct:元结构体
template <typename... Members>
struct meta_struct : meta_struct_impl<Members...> {};
作用:
- 一个元结构体由多个
member组合而成。 - 支持使用
{arg<"id"> = 42, arg<"name"> = "Tom"}的语法初始化。 - 可通过
get<"id">(ms)获取字段值。 - 支持模板元编程操作,比如
meta_struct_apply遍历所有成员。
5⃣ required 与 default_init
inline constexpr auto required = [] {};
required表示该字段必须在初始化时提供,否则编译时报错。
template <typename T>
struct default_init {
constexpr auto operator()() const {
if constexpr (std::is_default_constructible_v<T>) return T{};
}
};
default_init提供默认初始化,用于可选字段。
6⃣ meta_struct_apply:遍历元结构体成员
template <typename F, typename... MembersImpl>
constexpr decltype(auto) meta_struct_apply(F&& f, meta_struct_impl<MembersImpl...>& m) {
return std::forward<F>(f)(static_cast<MembersImpl&>(m)...);
}
作用:
- 将元结构体的每个成员展开并传给函数
f,方便批量操作,比如打印。
7⃣ get 与 get_attributes:
template <fixed_string tag, typename MetaStruct>
constexpr decltype(auto) get(MetaStruct&& s) {
return get_impl<tag>(std::forward<MetaStruct>(s));
}
作用:
- 通过标签在元结构体中获取对应成员的值。
get_attributes可以获取成员的属性(比如默认值、required标记等)。
8⃣ 使用示例:
using person_ref = meta_struct<
member<"name", std::string_view, required>,
member<"id", const int&, required>,
member<"score", const int&, required>
>;
void display_person_meta(person_ref p) {
std::cout << "id=" << get<"id">(p)
<< " name=" << get<"name">(p)
<< " score=" << get<"score">(p) << "\n";
}
解释:
person_ref是一个元结构体,包含三个必须提供的字段。- 可以用
get<"id">(p)等方式访问字段。 - 结构体与普通 C++ 对象的操作方式类似,但增加了编译期检查和元信息。
9⃣ 普通对象与元结构体的对比
struct MyPerson { std::string name; int id=0; int score=0; };
MyPersonMeta pm1; // 元结构体形式
display_person_meta(pm1); // 访问字段通过 get<>
- 普通对象直接通过
p.id、p.name访问。 - 元结构体通过
get<"id">(ms)访问,同时支持元信息(如required)。
总结
这个代码实现了一个 编译期元结构体库,核心特点:
- 字段可用标签访问,无需顺序依赖。
- 支持默认值与必填字段检查。
- 提供
meta_struct_apply遍历所有字段,方便批量操作。 - 可用在模板元编程、序列化、映射普通对象到元结构体等场景。
#include <algorithm>
#include <cstddef>
#include <optional>
#include <string_view>
#include <type_traits>
#include <string>
#include <iostream>
// 用于创建一个未初始化的 fixed_string
struct no_init_fixed_string {};
// ---------------------------
// fixed_string:编译期固定长度字符串
// ---------------------------
template <std::size_t N>
struct fixed_string {
char data[N + 1] = {}; // 存储字符,末尾含 '\0'
// 构造函数:从字符串字面量初始化
constexpr fixed_string(const char (&foo)[N + 1]) { std::copy_n(foo, N + 1, data); }
// 从 std::string_view 构造 fixed_string
constexpr static auto from_string_view(std::string_view s) {
fixed_string<N> fs{no_init_fixed_string{}}; // 先不初始化
std::copy(s.begin(), s.end(), fs.data);
return fs;
}
// 返回 std::string_view
constexpr std::string_view sv() const { return std::string_view(data); }
auto operator<=>(const fixed_string&) const = default; // 三向比较
constexpr fixed_string(no_init_fixed_string) : data{} {}; // 空初始化
constexpr std::size_t size() const { return N; }
};
// 支持从字符数组自动推导 fixed_string
template <std::size_t N>
fixed_string(const char (&str)[N]) -> fixed_string<N - 1>;
// ---------------------------
// tag_and_value:标签与值绑定
// ---------------------------
template <fixed_string Tag, typename T>
struct tag_and_value {
T value;
};
// 前置声明 meta_struct
template <typename... Members>
struct meta_struct_impl;
template <typename... Members>
struct meta_struct;
// 支持从成员列表自动推导 meta_struct 类型
template <typename... Members>
meta_struct(Members...) -> meta_struct<Members...>;
// 空 meta_struct_impl 和 meta_struct 特化
template <>
struct meta_struct_impl<> {};
template <>
struct meta_struct<> : meta_struct_impl<> {};
// ---------------------------
// parms:用于将标签和值批量组合
// ---------------------------
struct no_conversion {};
template <typename... TagsAndValues>
struct parms : TagsAndValues... {
constexpr operator no_conversion() const { return no_conversion{}; }
};
template <typename... TagsAndValues>
parms(TagsAndValues...) -> parms<TagsAndValues...>;
// ---------------------------
// default_init:默认初始化器
// ---------------------------
template <typename T>
struct default_init {
constexpr default_init() = default;
auto operator<=>(const default_init&) const = default;
constexpr auto operator()() const {
if constexpr (std::is_default_constructible_v<T>) {
return T{}; // 返回默认构造的 T
}
}
};
// ---------------------------
// call_init:根据初始化器初始化字段
// ---------------------------
template <fixed_string Tag, typename T, typename Self, typename F>
constexpr auto call_init(Self&, F& f)
requires(requires {
{ f() } -> std::convertible_to<T>;
})
{
return f();
}
template <fixed_string Tag, typename T, typename Self, typename F>
constexpr auto call_init(Self& self, F& f)
requires(requires {
{ f(self) } -> std::convertible_to<T>;
})
{
return f(self);
}
// 如果初始化器返回 void,表示必须提供值,否则报错
template <fixed_string Tag, typename T, typename Self, typename F>
constexpr auto call_init(Self& self, F& f)
requires(requires {
{ f() } -> std::same_as<void>;
})
{
static_assert(!std::is_same_v<decltype(f()), void>, "Required argument not specified");
}
// 表示字段必须在初始化时提供
inline constexpr auto required = [] {};
// ---------------------------
// member:元结构体成员
// ---------------------------
template <fixed_string Tag, typename T, auto Init = default_init<T>(), meta_struct Attributes = {}>
struct member {
using element_type = T;
T value;
// 标签、初始化器、属性
constexpr static auto tag() { return Tag; }
constexpr static auto init() { return Init; }
constexpr static auto attributes() { return Attributes; }
// 从 tag_and_value 初始化
template <typename Self, typename OtherT>
constexpr member(Self&, tag_and_value<Tag, OtherT> tv) : value(std::move(tv.value)) {}
// 使用默认初始化
template <typename Self>
constexpr member(Self& self, no_conversion) : value(call_init<Tag, T>(self, Init)) {}
// 支持 optional
template <typename Self>
constexpr member(Self& self,
tag_and_value<Tag, std::optional<std::remove_reference_t<T>>> tv_or)
requires(!std::is_reference_v<T>)
: value(tv_or.value.has_value() ? std::move(*tv_or.value) : call_init<Tag, T>(self, Init)) {
}
// 从其他 member 拷贝或移动构造
template <typename Self, typename OtherT, auto OtherInit, auto OtherAttributes>
requires(std::is_convertible_v<OtherT, T>)
constexpr member(Self&, const member<Tag, OtherT, OtherInit, OtherAttributes>& other)
: value(other.value) {}
template <typename Self, typename OtherT, auto OtherInit, auto OtherAttributes>
requires(std::is_convertible_v<OtherT, T>)
constexpr member(Self&, member<Tag, OtherT, OtherInit, OtherAttributes>&& other)
: value(std::move(other.value)) {}
// 拷贝和移动赋值
template <typename OtherT, auto OtherInit, auto OtherAttributes>
requires(std::is_convertible_v<OtherT, T>)
constexpr member& operator=(const member<Tag, OtherT, OtherInit, OtherAttributes>& other) {
value = other.value;
return *this;
}
template <typename OtherT, auto OtherInit, auto OtherAttributes>
requires(std::is_convertible_v<OtherT, T>)
constexpr member& operator=(member<Tag, OtherT, OtherInit, OtherAttributes>&& other) {
value = std::move(other.value);
return *this;
}
constexpr member(member&&) = default;
constexpr member(const member&) = default;
constexpr member& operator=(member&&) = default;
constexpr member& operator=(const member&) = default;
auto operator<=>(const member&) const = default; // 三向比较
};
// ---------------------------
// meta_struct_impl:实现类,继承所有成员
// ---------------------------
template <typename... Members>
struct meta_struct_impl : Members... {
// 通过 parms 初始化
template <typename... Args>
constexpr meta_struct_impl(parms<Args...> p) : Members(*this, std::move(p))... {}
// 默认构造,使用 no_conversion 初始化
constexpr meta_struct_impl() : Members(*this, no_conversion{})... {}
constexpr meta_struct_impl(meta_struct_impl&&) = default;
constexpr meta_struct_impl(const meta_struct_impl&) = default;
constexpr meta_struct_impl& operator=(meta_struct_impl&&) = default;
constexpr meta_struct_impl& operator=(const meta_struct_impl&) = default;
// 支持不同成员类型之间的拷贝和移动
template <typename... OtherMembers>
constexpr meta_struct_impl(meta_struct_impl<OtherMembers...>&& other)
: Members(*this, std::move(other))... {};
template <typename... OtherMembers>
constexpr meta_struct_impl(const meta_struct_impl<OtherMembers...>& other)
: Members(*this, other)... {};
template <typename... OtherMembers>
constexpr meta_struct_impl& operator=(meta_struct_impl<OtherMembers...>&& other) {
((static_cast<Members&>(*this) = std::move(other)), ...);
return *this;
};
template <typename... OtherMembers>
constexpr meta_struct_impl& operator=(const meta_struct_impl<OtherMembers...>& other) {
((static_cast<Members&>(*this) = other), ...);
return *this;
};
constexpr operator no_conversion() const { return no_conversion{}; }
auto operator<=>(const meta_struct_impl&) const = default;
};
// ---------------------------
// meta_struct:对外接口
// ---------------------------
template <typename... Members>
struct meta_struct : meta_struct_impl<Members...> {
using super = meta_struct_impl<Members...>;
template <typename... TagsAndValues>
constexpr meta_struct(TagsAndValues... tags_and_values)
: super(parms(std::move(tags_and_values)...)) {}
constexpr meta_struct() = default;
constexpr meta_struct(meta_struct&&) = default;
constexpr meta_struct(const meta_struct&) = default;
constexpr meta_struct& operator=(meta_struct&&) = default;
constexpr meta_struct& operator=(const meta_struct&) = default;
template <typename... OtherMembers>
constexpr meta_struct(meta_struct<OtherMembers...>&& other) : super(std::move(other)) {}
template <typename... OtherMembers>
constexpr meta_struct(const meta_struct<OtherMembers...>& other) : super(other) {}
template <typename... OtherMembers>
constexpr meta_struct& operator=(meta_struct<OtherMembers...>&& other) {
static_cast<super&>(*this) = std::move(other);
return *this;
}
template <typename... OtherMembers>
constexpr meta_struct& operator=(const meta_struct<OtherMembers...>& other) {
static_cast<super&>(*this) = other;
return *this;
}
auto operator<=>(const meta_struct&) const = default;
};
// ---------------------------
// arg_type / arg:构建 member 的语法糖
// ---------------------------
template <fixed_string Tag>
struct arg_type {
template <typename T>
constexpr auto operator=(T t) const {
return member<Tag, T>(*this, tag_and_value<Tag, T>(std::move(t)));
}
};
template <fixed_string Tag>
inline constexpr auto arg = arg_type<Tag>{};
// ---------------------------
// meta_struct_apply / meta_struct_for_each
// 遍历元结构体成员
// ---------------------------
template <typename F, typename... Members>
constexpr decltype(auto) meta_struct_apply(F&& f, meta_struct_impl<Members...>& m) {
return std::forward<F>(f)(static_cast<Members&>(m)...);
}
template <typename F, typename... Members>
constexpr decltype(auto) meta_struct_apply(F&& f, const meta_struct_impl<Members...>& m) {
return std::forward<F>(f)(static_cast<const Members&>(m)...);
}
template <typename F, typename... Members>
constexpr decltype(auto) meta_struct_apply(F&& f, meta_struct_impl<Members...>&& m) {
return std::forward<F>(f)(static_cast<Members&&>(m)...);
}
// 静态 apply
template <typename MetaStructImpl>
struct apply_static_impl;
template <typename... Members>
struct apply_static_impl<meta_struct_impl<Members...>> {
template <typename F>
constexpr static decltype(auto) apply(F&& f) {
return f(static_cast<Members*>(nullptr)...);
}
};
template <typename MetaStruct, typename F>
constexpr auto meta_struct_apply(F&& f) {
return apply_static_impl<typename MetaStruct::super>::apply(std::forward<F>(f));
}
// for_each 遍历
template <typename MetaStruct, typename F>
constexpr void meta_struct_for_each(F&& f, MetaStruct&& ms) {
meta_struct_apply([&](auto&... m) mutable { (std::forward<F>(f)(m), ...); },
std::forward<MetaStruct>(ms));
}
// ---------------------------
// get / get_attributes / has
// 获取成员值和属性
// ---------------------------
template <fixed_string tag, typename T, auto Init, auto Attributes>
constexpr decltype(auto) get_impl(member<tag, T, Init, Attributes>& m) {
return (m.value);
}
template <fixed_string tag, typename T, auto Init, auto Attributes>
constexpr decltype(auto) get_impl(const member<tag, T, Init, Attributes>& m) {
return (m.value);
}
template <fixed_string tag, typename T, auto Init, auto Attributes>
constexpr decltype(auto) get_impl(member<tag, T, Init, Attributes>&& m) {
return std::move(m.value);
}
template <fixed_string tag, typename MetaStruct>
constexpr decltype(auto) get(MetaStruct&& s) {
return get_impl<tag>(std::forward<MetaStruct>(s));
}
template <fixed_string tag, typename T, auto Init, auto Attributes>
constexpr member<tag, T, Init, Attributes> get_member_impl(
const member<tag, T, Init, Attributes>& m);
template <fixed_string Tag, typename MetaStruct>
constexpr auto get_attributes(MetaStruct&& s) {
return decltype(get_member_impl(s))::attributes();
}
template <fixed_string Tag, typename MetaStruct>
constexpr auto get_attributes() {
return decltype(get_member_impl<Tag>(std::declval<MetaStruct&>()))::attributes();
}
template <fixed_string tag, typename T, auto Init, auto Attributes>
constexpr std::true_type has_impl(const member<tag, T, Init, Attributes>&);
template <fixed_string tag, typename T, auto Init, auto Attributes>
constexpr std::false_type has_impl(no_conversion);
template <fixed_string tag, typename MetaStruct>
constexpr bool has(MetaStruct&& s) {
return decltype(has_impl<tag>(s))::value;
}
template <fixed_string tag, typename MetaStruct>
constexpr bool has() {
return decltype(has_impl<tag>(std::declval<MetaStruct&>()))::value;
}
// ---------------------------
// meta_struct_size:获取成员数量
// ---------------------------
template <typename... Members>
constexpr std::size_t meta_struct_size_impl(const meta_struct<Members...>*) {
return sizeof...(Members);
}
template <typename... Members>
constexpr std::size_t meta_struct_size(const meta_struct<Members...>&) {
return sizeof...(Members);
}
template <typename MetaStruct>
constexpr std::size_t meta_struct_size() {
return meta_struct_size_impl(static_cast<const MetaStruct*>(nullptr));
}
// ---------------------------
// 打印函数
// ---------------------------
template <typename MetaStruct>
void print(std::ostream& os, const MetaStruct& ms) {
meta_struct_apply(
[&](const auto&... m) {
auto print_item = [&](auto& m) { std::cout << m.tag().sv() << ":" << m.value << "\n"; };
(print_item(m), ...);
},
ms);
}
// ---------------------------
// 使用示例
// ---------------------------
using NameAndIdArgs = meta_struct<member<"name", std::string_view>, member<"id", const int&>>;
void print_name_id(NameAndIdArgs args) {
std::cout << "Name is " << get<"name">(args) << " and id is " << get<"id">(args) << "\n";
}
enum class encoding : int { fixed = 0, variable = 1 };
int main() {
// 定义一个 meta_struct 类型 Person,带默认值和 lambda 初始化
using Person = meta_struct< //
member<"id", int, required, {arg<"encoding"> = encoding::variable}>, //
member<"name", std::string, required>, //
member<"score", int, [](auto& self) { return get<"id">(self) + 1; }> //
>;
// 获取 id 字段的属性
constexpr auto attributes = get_attributes<"id", Person>();
if constexpr (has<"encoding">(attributes) &&
get<"encoding">(attributes) == encoding::variable) {
std::cout << "Encoding was variable";
} else {
std::cout << "Encoding was fixed";
}
// 打印函数
auto print = [](auto& t) {
meta_struct_apply(
[&](const auto&... m) { ((std::cout << m.tag().sv() << ":" << m.value << "\n"), ...); },
t);
};
// 初始化 Person 对象
Person p{arg<"id"> = 2, arg<"name"> = "John"};
print(p);
using NameAndId = meta_struct<member<"name", std::string_view>, member<"id", int>>;
NameAndId n = p; // 从 Person 拷贝部分字段
print(n);
print_name_id(p);
print_name_id(n);
static_assert(meta_struct_size<NameAndId>() == 2);
static_assert(meta_struct_size(n) == 2);
constexpr auto fs = fixed_string<4>::from_string_view("John");
}
好的,我来帮你用理解这个完整的 C++ 元结构体(meta_struct)实现和使用示例。我会按模块逐步解析:
1⃣ fixed_string:编译期固定长度字符串
template <std::size_t N>
struct fixed_string {
char data[N + 1] = {};
constexpr fixed_string(const char (&foo)[N + 1]) { std::copy_n(foo, N + 1, data); }
constexpr static auto from_string_view(std::string_view s) { ... }
constexpr std::string_view sv() const { return std::string_view(data); }
auto operator<=>(const fixed_string&) const = default;
constexpr fixed_string(no_init_fixed_string) : data{} {};
constexpr std::size_t size() const { return N; }
};
- 作用:在编译期就能保存固定长度的字符串,用作字段标签(tag)。
from_string_view可以从运行时std::string_view转为fixed_string。sv()返回std::string_view,方便打印或比较。operator<=>实现三向比较,可用于排序或相等性判断。no_init_fixed_string用于创建“未初始化”的对象,主要是为了from_string_view。
2⃣ member:元结构体的字段
template <fixed_string Tag, typename T, auto Init = default_init<T>(), meta_struct Attributes = {}>
struct member { ... };
- 字段标签:
Tag是fixed_string类型的字段名字。 - 字段类型:
T表示字段的数据类型。 - 默认值/初始化器:
Init可以是 lambda 或default_init。 - 属性:
Attributes可以用来给字段附加元信息,比如编码类型。
特点: - 可以用
tag_and_value或optional初始化。 - 支持从其他 member 拷贝或移动构造。
- 默认、拷贝、移动赋值都已经实现。
- 提供三向比较操作符
<=>。
3⃣ meta_struct / meta_struct_impl:元结构体
template <typename... Members>
struct meta_struct_impl : Members... { ... };
template <typename... Members>
struct meta_struct : meta_struct_impl<Members...> { ... };
- 原理:使用 多重继承,把每个字段
member都继承进来。 - 初始化:
- 可以传入
parms<...>批量初始化字段。 - 默认构造使用
no_conversion调用call_init。
- 可以传入
- 支持:
- 不同元结构体之间的拷贝/移动(部分字段匹配即可)。
- 获取字段数量、遍历字段、访问字段值。
4⃣ parms 和 tag_and_value:批量初始化
template <typename... TagsAndValues>
struct parms : TagsAndValues... {
constexpr operator no_conversion() const { return no_conversion{}; }
};
parms继承所有tag_and_value,方便批量初始化meta_struct。no_conversion用于标记“未提供值”,由call_init决定是否使用默认值或报错。
5⃣ arg / arg_type:初始化语法糖
template <fixed_string Tag>
inline constexpr auto arg = arg_type<Tag>{};
- 使用方式:
Person p{arg<"id"> = 2, arg<"name"> = "John"};
- 编译器会自动生成
tag_and_value<"id", int>和tag_and_value<"name", std::string>,然后传给meta_struct初始化字段。
6⃣ get / get_attributes / has:访问字段
get<"name">(person); // 获取字段值
get_attributes<"id", Person>(); // 获取属性
has<"encoding">(attributes); // 是否存在某个属性
- 灵活:支持 const、非 const、右值引用等不同访问方式。
- 属性系统允许给字段附加额外信息(例如编码类型)。
7⃣ 遍历和打印
meta_struct_apply([](auto&... m){ ... }, meta_struct_instance);
meta_struct_for_each([](auto& m){ ... }, meta_struct_instance);
meta_struct_apply可以把 lambda 应用到所有成员上。meta_struct_for_each用于遍历,每个成员逐一处理。- 打印示例:
auto print_item = [&](auto& m) { std::cout << m.tag().sv() << ":" << m.value << "\n"; };
(print_item(m), ...);
8⃣ 使用示例
using Person = meta_struct<
member<"id", int, required, {arg<"encoding"> = encoding::variable}>,
member<"name", std::string, required>,
member<"score", int, [](auto& self){ return get<"id">(self)+1; }>
>;
- 字段 id:必须提供值,附带属性
encoding::variable。 - 字段 name:必须提供值。
- 字段 score:自动计算
score = id + 1。
Person p{arg<"id"> = 2, arg<"name"> = "John"};
- 构造函数自动将 lambda 计算
score。 - 可通过
get<"score">(p)获取计算结果。 - 可以部分拷贝到其他 meta_struct:
NameAndId n = p;
- 静态检查:
static_assert(meta_struct_size<NameAndId>() == 2);
- 固定字符串转换:
constexpr auto fs = fixed_string<4>::from_string_view("John");
9⃣ 总结理解
- 元结构体 (
meta_struct) 是编译期反射的模拟:字段名、类型、默认值、属性全部可在编译期访问。 - 字段 (
member) 可以有默认值、lambda 初始化、属性和可选值。 - 标签 (
fixed_string) 允许用字符串字面量访问字段:get<"name">(person)。 - 初始化语法 使用
arg<"tag"> = value,可读性高。 - 操作方便:
get访问值get_attributes获取属性has检查字段或属性meta_struct_apply/for_each遍历meta_struct_size获取字段数量
- 设计目标:
- 编译期安全,字段名和值类型都在编译期校验
- 灵活支持 lambda 初始化、默认值和可选值
- 支持字段属性扩展(如编码类型)
更多推荐



所有评论(0)