在过去的 10 年中,一直在尝试向 C++ 添加反射。最新的提案是针对c++23,可能会也可能不会。
与大多数语言中的反射不同,c++ 反射的计划是编译时反射。所以在编译时,你可以对结构成员、函数和方法的参数和属性、枚举值和名称等进行反射。
然后您可以进行有限的具体化,注入有关您反映的内容的信息以生成其他类型和代码。
虽然这有点奇怪,但这意味着不使用反射的程序不会为此支付运行时间成本。它也非常强大。
最简单的例子就是你可以用它来实现运行时反射。
struct Member {
std::string_view name;
std::any_ref value;
};
struct Reflectable {
virtual std::span<Member> GetMembers() const = 0;
virtual std::span<Member> GetMembers() = 0;
};
template<class D>
struct ImplReflectable:Reflectable {
std::span<Member> GetMembers() const final;
std::span<Member> GetMembers() final;
};
template<class D>
std::span<Member> ImplReflectable<D>::GetMembers() const {
// compile time reflection code on D here
}
template<class D>
std::span<Member> ImplReflectable<D>::GetMembers() {
// compile time reflection code on D here
}
上面你写了一次,突然你想要反射的任何类型,你可以这样做:
struct Point : ImplReflectable<Point> {
int x, y;
};
一个反射系统附加到Point。
实现此运行时反射的库可以随心所欲地复杂和强大。每种类型都必须做一些工作(如上述)才能选择加入,但对于 UI 库(例如)这样做并不是一个严重的问题。不选择加入的类型继续 C++ 假设“如果你不使用它,就不要付费”。
但这仅仅是开始。一个提案,元类,许可:
interface Reflectable {
std::span<Member> GetMembers() const;
std::span<Member> GetMembers();
};
你可以有元类,或者接受类型并返回它们的函数。这允许您定义类的元类,例如用语言编写的“接口”。现在,interface 有点像玩具,但您可以编写 QObject 或 Reflectable 或 PolymorphicValueType 或 NetworkProtocol 元类来修改您的类定义的含义。
这可能会或可能不会进入c++23。它继续变得更好,但它也继续被推迟。对于大多数主要的 C++ 编译器,您可以尝试多种编译时反射实现。语法不断变化,因为有基于符号运算符的反射库、基于reflexpr 的运算符反射库,其中一些反射数据是类型,另一些是constexpr 对象和consteval 函数。