基于 C++26 静态反射实现零样板代码、零额外开销的分派表

C++26 引入的静态反射机制赋予了开发者在编译期获取 C++ 程序自身元信息的强大能力。利用 C++26 标准库的反射 API,我们可以查询任意一个 C++ 实体(变量、函数、类、模板、命名空间……)的元信息,其中最常用的就是名称、类型、所有下属成员以及所有基类。善用这些元信息可以帮助我们实现更加优雅且高效的 C++ 代码设计。本文从分派表(Dispatch table)这一高频使用场景入手,展示 C++26 反射的表达能力如何消除传统方式实现分派表所需的大量样板代码和难以避免的运行时开销,并循序渐进地拆解如何基于 C++26 反射不断迭代分派表的 API 设计。

本文所述内容为笔者实现的 rbox 库的一部分,实现源码已在 GitHub 开源。

Dispatch Table with C++26 Reflection - Zero Boilerplate & Zero Runtime Overhead

Manually translated from: 基于 C++26 静态反射实现零样板代码、零额外开销的分派表.

As compile-time reflection is finally adopted to C++26 standard, developers are enabled to fetch and operate on the metadata of the C++ program itself. Metadata of various C++ entities (variables, functions, classes, templates, namespaces, etc.) can be obtained from reflection API in C++26 standard library, the most frequently used of which is getting an entity’s name, type, list of members or list of base classes. Reflection is incredibly helpful to support more elegant and more efficient C++ code by utilizing the metadata properly. In this blog we dive into dispatch table, which is a common pattern in real-world C++ code, demonstrating how the great power and expressiveness of C++26 reflection helps with eliminating boilerplate code and runtime overhead that are inevitable in pre-C++26 dispatch table implementation, and then, how the API design of our reflection-based dispatch table can be further improved step-by-step.

The contents shown by this blog has full implementation in my rbox library. Source code is available in GitHub.

扩展 C++26 std::define_static_array() 的编译期数据提升能力

随着静态反射(Reflection)如愿成为 C++26 标准的一部分,C++ 标准库也提供了 std::define_static_array() 帮助我们在编译期将一个 range 提升为程序静态数据段的数组常量,尤其是在 constexpr 运算逻辑较为复杂的时候可以有效避免样板代码量以及元编程带来的编译期时空开销。然而,由于 std::define_static_array() 的内部实现原理是将被提升的元素全部作为 constexpr 模板变量的非类型模板参数(NTTP),因此可以被 std::define_static_array() 直接提升的类型也必须符合 NTTP 的全部限制,即元素类型必须为 structural:要么是 C++ 基本类型,要么只能是所有成员均为 public 且递归满足 structural 性质的结构体或联合体。但在实际开发中,我们更多是与非 structural 类型打交道,比如 std::define_static_array() 自己的返回类型 std::span<const T> 就不是 structural(其成员变量均为私有),这就导致 std::define_static_array() 自身难以胜任处理嵌套 range 的进阶任务。本文将介绍如何通过 C++26 强大的反射能力,并借助一些简易的标准库替代品,有效地扩展 std::define_static_array() 的数据提升能力,让更多原本非 structural 的类型(甚至是复杂的嵌套类型)也能顺利提升为编译期常量。

本文所述内容作为笔者实现的 rbox 库的核心组件之一。rbox::to_static_storage() 的实现源代码已在 GitHub 开源。

Extension to std::define_static_array() - More Powerful Compile-time Data Promotion

Manually translated from: 扩展 C++26 std::define_static_array() 的编译期数据提升能力

Compile-time reflection has been part of C++26 standard, and C++ standard library provides std::define_static_array() which promotes a range to a constant array in static data storage, effectively helping us to cut off boilerplate code and compile-time overhead with template metaprogramming especially when the constexpr evaluation is complex. However, std::define_static_array() has its own limitations that require the range value type to be structural, the same constraint to non-type template parameters (NTTP) due to the fact that std::define_static_array() is technically based on template instantiation internally. That is, the range value type is limited to C++ fundamental types, or structs or unions whose data members are structural recursively, etc., which is not the common case in real-world codebase. Even the result type of std::define_static_array() itself, which is std::span<const T>, is not structural due to its private data members, making nested range promotion difficult with std::define_static_array() alone. This blog shows how we can extend the ability of compile-time data promotion by utilizing the great power of C++26 reflection plus a few helper types as replacements to standard library, enabling more non-structural types (including complicated, nested ones) to be promoted as compile-time constant data.

The contents shown by this blog is one of the core components in my rbox library. The source code of rbox::to_static_storage() is available in my GitHub repository.