我希望能够自省一个c++类的名称,内容(即成员及其类型)等。这里我说的是原生c++,而不是托管c++,托管c++有反射。我意识到c++使用RTTI提供了一些有限的信息。哪些附加库(或其他技术)可以提供这些信息?
当前回答
这个问题现在有点老了(不知道为什么我今天一直在问老问题),但我在想BOOST_FUSION_ADAPT_STRUCT,它引入了编译时反射。
当然,这取决于你将其映射到运行时反射,这不会太容易,但在这个方向上是可能的,而不是在相反的方向上:)
我真的认为一个宏来封装BOOST_FUSION_ADAPT_STRUCT可以生成必要的方法来获得运行时行为。
其他回答
RareCpp库实现了相当简单和直观的反射——所有字段/类型信息都被设计成可以在数组中使用,或者感觉像是数组访问。它是为c++ 17编写的,可与Visual Studios、g++和Clang一起使用。这个库只有头文件,这意味着你只需要将“Reflect.h”复制到你的项目中就可以使用它。
被反射的结构体或类需要REFLECT宏,在该宏中您可以提供所反射的类的名称和字段的名称。
class FuelTank {
public:
float capacity;
float currentLevel;
float tickMarks[2];
REFLECT(FuelTank, capacity, currentLevel, tickMarks)
};
这就是全部内容,不需要额外的代码来设置反射。可选地,您可以提供类和字段注释,以便能够遍历超类或向字段添加额外的编译时信息(例如Json::Ignore)。
遍历字段可以简单到…
for ( size_t i=0; i<FuelTank::Class::TotalFields; i++ )
std::cout << FuelTank::Class::Fields[i].name << std::endl;
您可以通过对象实例循环访问字段值(您可以读取或修改)和字段类型信息……
FuelTank::Class::ForEachField(fuelTank, [&](auto & field, auto & value) {
using Type = typename std::remove_reference<decltype(value)>::type;
std::cout << TypeToStr<Type>() << " " << field.name << ": " << value << std::endl;
});
JSON库构建在RandomAccessReflection之上,它可以自动识别适当的JSON输出表示来读写,并且可以递归遍历任何反射字段,以及数组和STL容器。
struct MyOtherObject { int myOtherInt; REFLECT(MyOtherObject, myOtherInt) };
struct MyObject
{
int myInt;
std::string myString;
MyOtherObject myOtherObject;
std::vector<int> myIntCollection;
REFLECT(MyObject, myInt, myString, myOtherObject, myIntCollection)
};
int main()
{
MyObject myObject = {};
std::cout << "Enter MyObject:" << std::endl;
std::cin >> Json::in(myObject);
std::cout << std::endl << std::endl << "You entered:" << std::endl;
std::cout << Json::pretty(myObject);
}
上面的代码可以这样运行……
Enter MyObject:
{
"myInt": 1337, "myString": "stringy", "myIntCollection": [2,4,6],
"myOtherObject": {
"myOtherInt": 9001
}
}
You entered:
{
"myInt": 1337,
"myString": "stringy",
"myOtherObject": {
"myOtherInt": 9001
},
"myIntCollection": [ 2, 4, 6 ]
}
参见……
反映文档 反映实现 更多用法示例
编辑:更新的坏链接截至2017年2月7日。
我想没有人提到这一点:
在CERN,他们使用c++的全反射系统:
欧洲核子研究中心的反射。看起来效果很好。
您需要查看您正在尝试做什么,以及RTTI是否满足您的需求。我已经实现了自己的伪反射,用于某些非常特定的目的。例如,我曾经希望能够灵活地配置模拟输出内容。它需要在输出的类中添加一些样板代码:
namespace {
static bool b2 = Filter::Filterable<const MyObj>::Register("MyObject");
}
bool MyObj::BuildMap()
{
Filterable<const OutputDisease>::AddAccess("time", &MyObj::time);
Filterable<const OutputDisease>::AddAccess("person", &MyObj::id);
return true;
}
第一个调用将该对象添加到筛选系统,该系统调用BuildMap()方法以确定哪些方法可用。
然后,在配置文件中,你可以这样做:
FILTER-OUTPUT-OBJECT MyObject
FILTER-OUTPUT-FILENAME file.txt
FILTER-CLAUSE-1 person == 1773
FILTER-CLAUSE-2 time > 2000
通过一些涉及boost的模板魔法,可以在运行时(读取配置文件时)将其转换为一系列方法调用,因此相当高效。我不建议你这样做,除非你真的需要,但是,当你这样做的时候,你可以做一些非常酷的事情。
我也想要一匹小马,但小马不是免费的。: - p
http://en.wikibooks.org/wiki/C%2B%2B_Programming/RTTI是你将得到的。像您所考虑的反射——运行时可用的完整描述性元数据——在默认情况下c++中不存在。
我想你可能会对Dominic Filion写的“在c++中使用反射模板”这篇文章感兴趣。它在Game Programming Gems 5的1.4部分。不幸的是,我没有带我的副本,但你可以找找看,因为我认为它解释了你想要的东西。
推荐文章
- 是否需要手动关闭ifstream?
- BindingFlags。IgnoreCase不为Type.GetProperty()工作?
- 为什么函数指针定义可以使用任意数量的&号或星号* ?
- 为什么我必须通过this指针访问模板基类成员?
- 什么是可重入函数?
- 什么是栈展开?
- 我如何读整个文件到性病::字符串在c++ ?
- 如何在c++中使用枚举
- 为什么512x512矩阵的转置比513x513矩阵的转置慢得多?
- 在Java中检查一个类对象是否是另一个类对象的子类
- 如何在underscore.js模板中使用if语句?
- 通过引用传递数组
- 如何获得具有给定属性的属性列表?
- 为什么非const引用不能绑定到临时对象?
- sizeof(某个指针)总是等于4吗?