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


当前回答

我想你可能会对Dominic Filion写的“在c++中使用反射模板”这篇文章感兴趣。它在Game Programming Gems 5的1.4部分。不幸的是,我没有带我的副本,但你可以找找看,因为我认为它解释了你想要的东西。

其他回答

我建议使用Qt。

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

如果你正在寻找相对简单的c++反射——我从各种来源的宏/定义中收集了它们,并注释了它们的工作方式。你可以下载页眉 这里的文件:

https://github.com/tapika/TestCppReflect/blob/master/MacroHelpers.h

一组定义,加上它上面的功能:

https://github.com/tapika/TestCppReflect/blob/master/CppReflect.h https://github.com/tapika/TestCppReflect/blob/master/CppReflect.cpp https://github.com/tapika/TestCppReflect/blob/master/TypeTraits.h

示例应用程序驻留在git存储库以及,在这里: https://github.com/tapika/TestCppReflect/

我将部分复制在这里并进行解释:

#include "CppReflect.h"
using namespace std;


class Person
{
public:

    // Repack your code into REFLECTABLE macro, in (<C++ Type>) <Field name>
    // form , like this:

    REFLECTABLE( Person,
        (CString)   name,
        (int)       age,
...
    )
};

void main(void)
{
    Person p;
    p.name = L"Roger";
    p.age = 37;
...

    // And here you can convert your class contents into xml form:

    CStringW xml = ToXML( &p );
    CStringW errors;

    People ppl2;

    // And here you convert from xml back to class:

    FromXml( &ppl2, xml, errors );
    CStringA xml2 = ToXML( &ppl2 );
    printf( xml2 );

}

REFLECTABLE定义使用类名+字段名+偏移量-来标识特定字段位于内存中的哪个位置。我已经尽可能地学习。net术语,但是c++和c#是不同的,所以不是一对一的。整个c++反射模型驻留在TypeInfo和FieldInfo类中。

我已经使用pugi xml解析器获取演示代码到xml并从xml恢复回来。

演示代码的输出如下所示:

<?xml version="1.0" encoding="utf-8"?>
<People groupName="Group1">
    <people>
        <Person name="Roger" age="37" />
        <Person name="Alice" age="27" />
        <Person name="Cindy" age="17" />
    </people>
</People>

也可以通过TypeTraits类和部分模板规范来启用任何第三方类/结构支持-以类似于CString或int的方式定义自己的TypeTraitsT类-参见中的示例代码

https://github.com/tapika/TestCppReflect/blob/master/TypeTraits.h#L195

该解决方案适用于Windows / Visual studio。它可以移植到其他操作系统/编译器,但还没有这样做。(如果你真的喜欢解决方案,请问我,我可能会帮助你)

该解决方案适用于一个类和多个子类的一次序列化。

然而,如果你正在寻找序列化类部分的机制,甚至是控制反射调用产生的功能,你可以看看下面的解决方案:

https://github.com/tapika/cppscriptcore/tree/master/SolutionProjectModel

更详细的信息可以从youtube视频中找到:

c++运行时类型反射 https://youtu.be/TN8tJijkeFE

我试图更深入地解释c++反射是如何工作的。

示例代码如下所示:

https://github.com/tapika/cppscriptcore/blob/master/SolutionProjectModel/testCppApp.cpp

c.General.IntDir = LR"(obj\$(ProjectName)_$(Configuration)_$(Platform)\)";
c.General.OutDir = LR"(bin\$(Configuration)_$(Platform)\)";
c.General.UseDebugLibraries = true;
c.General.LinkIncremental = true;
c.CCpp.Optimization = optimization_Disabled;
c.Linker.System.SubSystem = subsystem_Console;
c.Linker.Debugging.GenerateDebugInformation = debuginfo_true;

但是这里的每一步实际上都会导致函数调用 使用c++属性__declspec(property(get =, put…).

它以路径的形式接收有关c++数据类型、c++属性名和类实例指针的全部信息,并根据这些信息生成xml、json,甚至在互联网上序列化这些信息。

这样的虚拟回调函数的例子可以在这里找到:

https://github.com/tapika/cppscriptcore/blob/master/SolutionProjectModel/VCConfiguration.cpp

参见函数ReflectCopy和虚函数::OnAfterSetProperty。

但是因为这个话题很高级,我建议先看视频。

如果您有一些改进的想法,请随时与我联系。

您需要查看您正在尝试做什么,以及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的模板魔法,可以在运行时(读取配置文件时)将其转换为一系列方法调用,因此相当高效。我不建议你这样做,除非你真的需要,但是,当你这样做的时候,你可以做一些非常酷的事情。

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。