如何向 C 应用程序添加反射?

新手上路,请多包涵

我希望能够自省 C++ 类的名称、内容(即成员及其类型)等。我在这里说的是本地 C++,而不是托管 C++,它有反射。我意识到 C++ 使用 RTTI 提供了一些有限的信息。哪些额外的库(或其他技术)可以提供这些信息?

原文由 Nick 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 767
2 个回答

Ponder 是一个 C++ 反射库,用于回答这个问题。我考虑了这些选项并决定自己制作,因为我找不到一个能满足我所有条件的选项。

尽管这个问题有很好的答案,但我不想使用大量的宏,或者依赖 Boost。 Boost 是一个很棒的库,但是有很多小型定制 C++0x 项目更简单,编译时间更快。能够在外部装饰一个类也有好处,比如包装一个(还没有?)支持 C++11 的 C++ 库。它是 CAMP 的分支,使用 C++11, 不再需要 Boost

原文由 Nick 发布,翻译遵循 CC BY-SA 3.0 许可协议

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 ]
}

也可以看看…

原文由 TheNitesWhoSay 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题