CPP Reflection in Action
- 反射的定义
- Evaluating Reflection Support in C++23
- Preview: C++26 Compile-Time Reflection (P2996, P1306)
- C++ 反射的实现方式
- Refer
反射的定义
Reflection: Introspection (内省) + Intercession (调解)
- Introspection: Ability of a program to examine itself
-
Intercession: Ability of a program to modify itself
-
Runtime feature of modern programming languages: Java, C#, Go, …
- Use cases: Code generation
- Serialization
- O/R-Mapping
- CLI Argument Parsing
- …
反射 (Reflection
) 是程序在运行时动态访问、检测和修改自身结构的能力,包括类型信息、成员变量、方法等元数据的操作。其核心功能可分为:
- 内省 (Introspection):运行时获取类型名称、成员列表、继承关系等元信息
- 动态操作:通过类型名创建对象、调用方法、修改属性值
- 元编程支持:结合代码生成技术实现编译时反射(如 C++ 提案
P2996
)
C++ 的挑战在于缺乏原生反射支持,需通过 RTTI
、宏、模板或第三方库实现。例如 Java 的 Class
对象可直接获取元信息,而 C++ 的 typeid
仅能提供有限类型名称。
Evaluating Reflection Support in C++23
- Introspection (runtime):
- Run-time type information (
RTTI
)
- Run-time type information (
- Introspection (compile-time):
- Type Traits
- Template metaprogramming
- Concepts and constraints
- Intercession (compile-time):
- Template metaprogramming
- Compile-time function execution
- Preprocessor metaprogramming
Preview: C++26 Compile-Time Reflection (P2996, P1306)
示例代码 (TODO: 有编译错误 )
#include <print>
#include <string>
#include <experimental/meta>
template<typename T>
requires std::is_class_v<T>
void print(const T& self) {
namespace meta = std::meta;
template for(constexpr meta::info i : meta::define_static_array(meta::nonstatic_data_members_of(^^T))) {
std::println("{} = {}", meta::identifier_of(i), self.[:i:]);
}
}
struct test {
int x;
double y;
std::string z;
};
int main() {
test t{1, 3,14, "hello"};
print(t);
}
C++ 反射的实现方式
基于 RTTI 的有限反射
运行期的类型,C++ 里挺有争议(跟异常类似)的功能 RTTI
。(还是要强调一句,你应该考虑是否用虚函数可以达到你需要的功能。很多项目,如 Google 的,会禁用 RTTI
。)
可以用 typeid
直接来获取对象的实际类型,例如:
#include <iostream>
#include <typeinfo>
#include <boost/core/demangle.hpp>
using namespace std;
using boost::core::demangle;
class shape {
public:
virtual ~shape() {}
};
class circle : public shape {
};
int main()
{
shape* ptr = new circle();
auto& type = typeid(*ptr);
cout << type.name() << endl;
cout << demangle(type.name()) << endl;
cout << boolalpha;
cout << (type == typeid(shape) ? "is shape\n" : "");
cout << (type == typeid(circle) ? "is circle\n" : "");
delete ptr;
}
在 GCC 下的输出:
6circle
circle
is circle