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


当前回答

这些信息确实存在——但不是你需要的格式,而且只有当你导出你的类时。这适用于Windows,我不知道其他平台。使用存储类说明符,例如:

class __declspec(export) MyClass
{
public:
    void Foo(float x);
}

这使得编译器将类定义数据构建到DLL/Exe中。但它不是一种可以用于反射的格式。

在我的公司,我们建立了一个解释元数据的库,允许你在不插入额外的宏等到类本身的情况下反映一个类。它允许如下方式调用函数:

MyClass *instance_ptr=new MyClass;
GetClass("MyClass")->GetFunction("Foo")->Invoke(instance_ptr,1.331);

这有效地做到:

instance_ptr->Foo(1.331);

Invoke(this_pointer,…)函数有可变参数。显然,通过这样调用函数,你可以绕过诸如const-safety之类的东西,所以这些方面是作为运行时检查实现的。

我相信语法可以改进,到目前为止它只适用于Win32和Win64。我们发现它非常有用,可以为类提供自动GUI接口,在c++中创建属性,流到XML和从XML输出等等,而且不需要从特定的基类派生。如果有足够的需求,也许我们可以把它做成样子发布。

其他回答

编辑:不再维护CAMP;有两个fork可供选择:

其中一个也被称为CAMP,并且基于相同的API。 思考是部分重写,应该优先考虑,因为它不需要Boost;它使用c++ 11。


CAMP是MIT授权的库(以前是LGPL),它向c++语言添加了反射。它在编译中不需要特定的预处理步骤,但是必须手动进行绑定。

目前的Tegesoft库使用Boost,但也有一个使用c++ 11的分支不再需要Boost。

如果你正在寻找相对简单的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。

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

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

我建议使用Qt。

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

我想宣传一下自动自省/反射工具包“IDK”的存在。它使用类似Qt的元编译器,并将元信息直接添加到目标文件中。据说它很容易使用。没有外部依赖。它甚至允许您自动反映std::string,然后在脚本中使用它。请看IDK

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中继。