我希望能够自省一个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部分。不幸的是,我没有带我的副本,但你可以找找看,因为我认为它解释了你想要的东西。