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


当前回答

c++中还有另一个用于反射的新库,叫做RTTR(运行时类型反射,参见github)。

该接口类似于c#中的反射,并且不需要任何RTTI。

其他回答

我建议使用Qt。

有一个开源许可证和一个商业许可证。

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++的全反射系统:

欧洲核子研究中心的反射。看起来效果很好。

c++的开箱即用不支持反射。这很可悲,因为它让防御性测试变得很痛苦。

有几种进行反思的方法:

使用调试信息(不可移植)。 在代码中加入宏/模板或其他源代码方法(看起来很难看) 修改编译器(如clang/gcc)以生成数据库。 使用Qt moc方法 提高反映 精确平坦的反射

第一个链接看起来最有希望(使用mod的clang),第二个讨论了一些技术,第三个是使用gcc的不同方法:

http://www.donw.org/rfl/ https://bitbucket.org/dwilliamson/clreflect https://root.cern.ch/how/how-use-reflex

现在有一个c++反射工作组。查看c++ 14 @ CERN的新闻:

https://root.cern.ch/blog/status-reflection-c

编辑13/08/17:

自最初的帖子以来,已经有了一些关于反思的潜在进展。下面提供了关于各种技术和状态的更多细节和讨论:

简要介绍静态反射 静态的反射 静态反射设计

然而,在不久的将来,在c++中实现标准化的反射方法看起来并不有希望,除非社区对支持c++中的反射有更多的兴趣。

下面是基于上次c++标准会议反馈的当前状态:

对反思建议的反思

编辑13/12/2017

Reflection看起来正在向c++ 20或更高版本的TSR迈进。然而运动是缓慢的。

镜子 镜像标准方案 镜纸 包括反射在内的元编程

编辑15/09/2018

TS草案已送交国家机构进行投票。

文本可以在这里找到:https://github.com/cplusplus/reflection-ts

编辑11/07/2019

反射TS已完成功能,并将于2019年夏天接受评论和投票。

元模板编程方法将被更简单的编译时代码方法所取代(在TS中没有反映出来)。

TS草案截至2019-06-17

编辑10/02/2020

这里有一个在Visual Studio中支持反射TS的请求:

https://developercommunity.visualstudio.com/idea/826632/implement-the-c-reflection-ts.html

作者David Sankel谈论TS:

http://cppnow.org/history/2019/talks/ https://www.youtube.com/watch?v=VMuML6vLSus&feature=youtu.be

2020年3月17日

反思正在取得进展。“2020-02布拉格ISO c++委员会旅行报告”的报告可以在这里找到:

https://www.reddit.com/r/cpp/comments/f47x4o/202002_prague_iso_c_committee_trip_report_c20_is/

关于c++ 23正在考虑的细节可以在这里找到(包括关于反射的简短部分):

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p0592r4.html

2020年6月4日

Jeff Preshing发布了一个名为“胶合板”的新框架,它包含了一种运行时反射机制。详情请点击这里:

https://preshing.com/20200526/a-new-cross-platform-open-source-cpp-framework/

到目前为止,这些工具和方法看起来是最完善和最容易使用的。

2020年7月12日编辑

叮当实验反射叉:https://github.com/lock3/meta/wiki

有趣的反射库,使用clang工具库提取信息进行简单的反射,不需要添加宏:https://github.com/chakaz/reflang

2021年2月24日编辑

一些额外的clang工具方法:

https://github.com/Celtoys/clReflect https://github.com/mlomb/MetaCPP

2021年8月25日编辑

youtube https://www.youtube.com/watch?v=60ECEc-URP8上的ACCU在线演讲也很值得一听,它讨论了当前对标准的建议和基于clang的实现。

See:

https://github.com/lock3/meta,分支论文/p2320 编译器资源管理器:https://cppx.godbolt.org/编译器版本使用p2320中继。

Ponder是一个c++反射库,用于回答这个问题。我考虑了这些选择,决定自己做一个,因为我找不到一个符合我所有要求的。

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