贴的这段 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 的结构体,里面有三个成员:idnamescore
  • idscore 有默认值,name 没有默认值,所以必须初始化。
int main() {
    person p{.id = 1, .name = "John"};  // 使用 C++20 设计器初始化,给 id 和 name 赋初值
  • pperson 类型的对象。
  • .id = 1id 成员赋值 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;
}
  • 打印输出当前 pidname,结果会是:
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 很方便,但有以下限制:
  1. 不能在编译期获取成员名字 → 影响自动序列化等场景。
  2. 不能根据编译期数据自动生成新的 struct 类型。
  3. 无法声明必填成员。
  4. 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>
    >;
    
    
    就是把 idname 组合到一起形成 Person 类型。

4⃣ get_implget

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.idinstance.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";

理解:

  1. 定义一个 Person 类型,包含两个成员:id(int)和 name(string)。
  2. 创建 Person p 实例。
  3. get<"id">(p)get<"name">(p) 设置成员值。
  4. 输出成员值,结果是:
    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 元结构体,成员为 idname
  • 初始化可以顺序无关,通过标签匹配。
  • get<"id"> 获取值。
  • 输出:
1 John
1 John

核心思想总结

  1. 编译期字符串 + 模板 实现标签。
  2. 多继承 + 参数包 实现成员聚合。
  3. 标签初始化:顺序无关,通过 arg<"tag"> = value 生成 tag_and_value
  4. 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
}

核心理解:

  1. fixed_string:用于编译期字符串,作为模板非类型参数。
  2. arg<“tag”> = value:生成 tag_and_value 对象,用于按标签初始化。
  3. member:每个元结构体成员,支持默认值和按标签初始化。
  4. meta_struct:将多个成员聚合,提供顺序无关的初始化。
  5. get<“tag”>(obj):通过标签获取成员值,实现类似编译期反射。
  6. 默认初始化 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};
    

总结理解

  1. 使用 fixed_string 作为标签,实现编译期标签系统
  2. arg<"tag">=value 生成 tag_and_value,用于按标签初始化成员。
  3. member 可带默认值或显式初始化。
  4. meta_struct 聚合多个 member,支持顺序无关的初始化。
  5. 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";
}

关键点理解

  1. 固定字符串标签 fixed_string 让标签在编译期确定,可用于模板非类型参数。
  2. 按标签初始化:通过 arg<"tag">=value 构造成员。
  3. 默认初始化器 default_init 或 lambda 支持成员自定义默认值。
  4. 依赖初始化:score 的 lambda 可以访问 self,即整个结构体对象,实现“成员依赖其他成员初始化”。
  5. 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_valuearg<"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_initcall_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 支持:
    1. 无参数初始化 Init()
    2. 带结构体引用初始化 Init(self),允许依赖其他成员
    3. 返回 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_implmeta_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 使用默认值 0
  • name 使用默认值 "John"
  • score 依赖 id 初始化,结果为 id+1 = 1
  • 输出:0 John 1

核心概念

  1. 编译期标签 + 元结构体:实现类似反射的访问方式。
  2. 成员依赖初始化:通过 Self& lambda 可以让一个成员依赖其他成员。
  3. 灵活初始化:支持标签初始化和默认初始化,顺序无关。
#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);
}

理解

  1. 固定字符串 fixed_string 用于在编译期表示标签。
  2. member<Tag, T, Init> 表示一个成员,支持:
    • 默认初始化
    • 依赖其他成员的初始化(通过 Self& lambda)
    • 标签值初始化
  3. meta_struct 聚合所有成员,支持:
    • 标签初始化(顺序无关)
    • 默认构造(调用每个成员的 Init)
    • meta_struct_apply 可以遍历成员类型或实例
  4. get<Tag>(obj) 可以通过标签获取成员值。
  5. 编译期与运行时结合
    • 可以在编译期获取成员类型或标签
    • 运行时可以直接访问成员值
#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);
}

理解

  1. fixed_string:编译期字符串,作为模板非类型参数(标签)。
  2. tag_and_value:标签 + 值组合,支持初始化成员。
  3. parms:参数包,可聚合多个 tag_and_value,并可安全转换为 no_conversion
  4. member<Tag, T, Init>
    • 支持标签值初始化
    • 支持默认初始化
    • 支持依赖其他成员初始化(通过 lambda)
    • 支持 optional 值覆盖默认值
  5. meta_struct:聚合多个成员,支持标签初始化和默认初始化。
  6. meta_struct_apply:遍历结构体成员,执行给定函数。
  7. get(obj):根据标签获取成员值。
  8. 示例
    • 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_valuearg_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_initcall_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,则不做操作。
      例子
member<"score", int, [](auto& self){ return get<"id">(self)+1; }>
  • score 的值依赖同一个 meta_structid 成员。

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)) {}
};
  • 功能
    1. 可以通过 tag_and_value 初始化。
    2. 如果未指定值,使用默认初始化器。
    3. 支持 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 优先覆盖。
    • 标签初始化方式清晰,类似命名参数。

总结

  1. 模板元结构体 + 固定标签实现了类似命名参数依赖初始化
  2. 优先级
    1. 如果提供 tag_and_value 且是非 optional → 使用它。
    2. 如果是 optional 且有值 → 使用值。
    3. 否则 → 调用默认初始化器。
  3. 灵活性
    • 可用于序列化、配置管理、数据绑定。
    • 所有成员在编译期可遍历。
  4. 优点
    • 无运行时字符串。
    • 类型安全,避免手动索引。
    • 支持依赖计算。
#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";
}

注解总结

  1. fixed_string → 编译期标签,用于模板参数。
  2. arg<"tag"> = value → 类似命名参数初始化。
  3. required → 标记必须提供的参数。
  4. member → 单个成员支持默认值、依赖初始化、optional 覆盖。
  5. meta_struct → 聚合多个成员,提供 get/apply 功能。
  6. 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_valuearg

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⃣ requireddefault_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) { ... }
  • 支持三种初始化方式:
    1. f() 返回类型可转换到 T
    2. f(self) 返回类型可转换到 T
    3. 返回 void → 报错,表示必填参数未提供
      作用:支持依赖其他成员的初始化(延迟初始化)。

5⃣ member — 单个成员

template <fixed_string Tag, typename T, auto Init = default_init<T>()>
struct member { ... };
  • 核心成员 value
  • 支持三种构造方式:
    1. tag_and_value 初始化
    2. 默认初始化(可依赖 self
    3. 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)
  • 对应 membervalue
  • 支持左值、右值、const

9⃣ 示例:Personsubstr

using Person = meta_struct<
    member<"id", int, required>,
    member<"name", std::string, required>,
    member<"score", int, [](auto& self) { return get<"id">(self) + 1; }>
>;

  • idname 必须提供
  • score 默认等于 id + 1 → 演示依赖初始化
  • 初始化顺序:
    1. id
    2. name
    3. 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})

核心思想

  1. 使用 固定字符串模板 做编译期标签
  2. member 封装每个成员,支持依赖、默认值、optional 覆盖
  3. meta_struct 聚合多个 member
  4. arg<"tag"> = value 提供命名参数初始化
  5. meta_struct_apply 遍历所有成员,支持打印、计算、依赖初始化

10⃣ 输出示例

The tags are: id name score
2 John 3
id:2
name:JRB
score:3
Hello World
Hello
World
  • 展示了:
    1. 标签顺序
    2. 成员初始化和默认值
    3. 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);
}

总结

  1. fixed_string → 编译期标签
  2. member → 封装单个成员,可依赖初始化、optional 覆盖
  3. meta_struct → 聚合多个成员,实现类似 Python dataclass / struct-of-named-fields 的功能
  4. arg<“tag”> = value → 命名参数构造
  5. 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 表示一个字段(比如 idname)。
  • 可指定默认值 Initrequired
  • 可以从 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⃣ requireddefault_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⃣ getget_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.idp.name 访问。
  • 元结构体通过 get<"id">(ms) 访问,同时支持元信息(如 required)。

总结

这个代码实现了一个 编译期元结构体库,核心特点:

  1. 字段可用标签访问,无需顺序依赖。
  2. 支持默认值与必填字段检查
  3. 提供 meta_struct_apply 遍历所有字段,方便批量操作。
  4. 可用在模板元编程、序列化、映射普通对象到元结构体等场景。
#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 { ... };
  • 字段标签Tagfixed_string 类型的字段名字。
  • 字段类型T 表示字段的数据类型。
  • 默认值/初始化器Init 可以是 lambda 或 default_init
  • 属性Attributes 可以用来给字段附加元信息,比如编码类型。
    特点:
  • 可以用 tag_and_valueoptional 初始化。
  • 支持从其他 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⃣ parmstag_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⃣ 总结理解

  1. 元结构体 (meta_struct) 是编译期反射的模拟:字段名、类型、默认值、属性全部可在编译期访问。
  2. 字段 (member) 可以有默认值、lambda 初始化、属性和可选值。
  3. 标签 (fixed_string) 允许用字符串字面量访问字段:get<"name">(person)
  4. 初始化语法 使用 arg<"tag"> = value,可读性高。
  5. 操作方便
    • get 访问值
    • get_attributes 获取属性
    • has 检查字段或属性
    • meta_struct_apply / for_each 遍历
    • meta_struct_size 获取字段数量
  6. 设计目标
    • 编译期安全,字段名和值类型都在编译期校验
    • 灵活支持 lambda 初始化、默认值和可选值
    • 支持字段属性扩展(如编码类型)
Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐