实现数组的结构体

这篇文章主要介绍了使用 C++26 Reflection 实现类似 Zig 中的 MultiArrayList 的功能,具体内容如下:

  • 背景与目标:作者观看了 Andrew Kelley 关于 Practical Data Oriented Design 的演讲,受其启发用 C++26 Reflection 实现相同功能。目标是实现一个 SoaVector<T>,它不是 T 的动态数组,而是为 T 的每个非静态数据成员都有一个动态数组。
  • 存储实现:以简单的 Point 结构为例,最初的存储方式类似 std::vector<Point>,但要实现 SoaVector<Point>,需要将 xy 分别存储,通过 C++26 Reflectionstd::meta::define_aggregate() 函数来定义聚合,存储方式改为 struct { char* x; int* y; size_t size; size_t capacity; }
  • 添加元素操作:实现 push_back 函数,基本轮廓与常规 Vector 相似,但需要考虑内存分配和复制。通过 std::define_static_array() 创建静态存储数组,按顺序处理每个非静态数据成员的分配、复制和释放。同时在 grow 函数和析构函数中正确管理内存。
  • 读取元素操作

    • 值索引:实现 const 索引操作符 operator[],可以成功读取 Point 元素。通过展开包的方式,一次性读取所有成员,提高效率。
    • 引用索引:为了支持写入操作,生成新的 PointRef 类型,包含对 xy 的引用,并添加赋值和转换运算符。索引操作符返回 PointRef,实现了对元素的读写操作。
    • 格式化引用:通过添加注释 format_as,在格式化时强制将 Ref 转换为 Point,使打印输出更符合预期。
  • 完整实现与对比:给出了 SoaVector 的完整实现代码,小于 100 行代码加上一些辅助函数。与 Zig 的 MultiArrayList 实现进行对比,Zig 做了额外的优化,将单个分配分割成块,并使用 enum 来处理字段。Zig 中一些特性如初始化类型、constexpr 函数参数、隐式命名枚举等值得借鉴。

总之,作者对 C++26 Reflection 感到非常兴奋,认为它为实现类似功能提供了有力的工具。

阅读 25
0 条评论