【问题标题】:Attribute & Reflection libraries for C++?C++ 的属性和反射库?
【发布时间】:2008-09-17 21:36:58
【问题描述】:

大多数成熟的 C++ 项目似乎都有自己的反射和属性系统,即用于定义可以通过字符串访问并自动序列化的属性。至少我参与的许多 C++ 项目似乎都在重新发明轮子。

您是否知道任何支持反射和属性容器的优秀的 C++ 开源库,具体来说:

  • 通过宏定义 RTTI 和属性
  • 通过代码访问 RTTI 和属性
  • 属性的自动序列化
  • 监听属性修改(例如 OnValueChanged)

【问题讨论】:

    标签: c++ reflection attributes


    【解决方案1】:

    有一个使用完全不同的方法在 C++ 中提供反射的新项目:CAMP。 https://github.com/tegesoft/camp

    CAMP 不使用预编译器,类/属性/函数/... 是使用类似于 boost.python 或 luabind 的语法手动声明的。当然,如果他们愿意,人们可以使用 gccxml 或 open-c++ 之类的预编译器来生成此声明。

    它仅基于纯 C++ 和 boost 头文件,并且由于模板元编程的强大功能,它支持任何类型的可绑定实体(例如,继承和奇怪的构造函数不是问题)。

    它是根据 MIT 许可证(以前的 LGPL)分发的。

    【讨论】:

    【解决方案2】:

    这就是当 C++ 遇到反射时你得到的:

    无论您选择什么,它都可能包含可怕的宏、难以调试的代码或奇怪的构建步骤。我见过一个系统自动从 DevStudio 的 PDB 文件生成序列化代码。

    说真的,对于小型项目,编写保存/加载函数(或使用流式操作符)会更容易。事实上,这也可能适用于大型项目 - 很明显,如果结构发生变化,您通常需要更改代码。

    【讨论】:

    • 除非我的应用程序已经使用 Qt,否则我会为需要保存的每个类创建流式操作符。
    • +1 : 照片 ;) 开玩笑。我同意这个结论。使用手工序列化器或使用其他语言:)
    • 货车字体有错别字,应该是l337!
    【解决方案3】:

    您可以看看下面的两个工具。我从来没有使用过它们,所以我不能告诉你它们有多实用。

    XRTTI:

    Xrtti 是一个工具和附带的 C++ 库,它扩展了 C++ 的标准运行时类型系统,以提供一组更丰富的关于类和方法的反射信息来操作这些类及其成员。

    OpenC++:

    OpenC++ 是 C++ 前端库(lexer+parser+DOM/MOP)和源到源的翻译器。 OpenC++ 支持开发 C++ 语言工具、扩展、特定领域的编译器优化和运行时元对象协议。

    【讨论】:

    • XRTTI 仍然有适用于后期 Linux 发行版的更新版本。 OpenC++ 好像太老了。
    【解决方案4】:

    我看了这些东西很长一段时间,但它们往往非常严厉。它们可能会阻止您使用继承,或使用奇怪的构造函数等。最终,它们最终成为过多的负担而不是便利。

    我现在使用的这种公开成员的方法非常轻量级,例如,您可以探索一个用于序列化的类或将所有名为“x”的字段设置为 0。它也是静态确定的,因此非常非常快。无需担心会干扰构建过程的库代码或代码生成层。它推广到嵌套类型的层次结构。

    使用一些宏设置您的编辑器,以自动编写其中的一些内容。

    struct point
    {
         int x;
         int y;
    
         // add this to your classes
         template <typename Visitor>
         void visit(Visitor v)
         {
             v->visit(x, "x"); 
             v->visit(y, "y");
         }
    };
    
    
    /** Outputs any type to standard output in key=value format */
    struct stdout_visitor
    {
         template <typename T>
         void visit(const T& rhs)
         {
             rhs.visit(this);
         }
    
         template <typename Scalar>
         void visit (const Scalar& s, const char* name)
         {
              std::cout << name << " = " << s << " ";
         }
    }
    

    【讨论】:

    • 虽然我喜欢它,但应该注意它不是一个通用的解决方案 - 例如一旦不知道实际的静态类型,它就会中断。
    • 这是一个好方法。我曾经做过一个预处理器,可以为你生成visit() 函数模板。然后是一些函子来序列化和反序列化 JSON、二进制、文本等......没有丑陋的宏。 groups.google.com/d/msg/comp.lang.c++/Ila1Tn09mm4/nJVxl3SzpFUJ
    【解决方案5】:

    这通常是 C++ 语言的一个臭名昭著的弱点,因为需要标准化以使反射实现具有可移植性和价值的东西不是标准的。我想到了调用约定、对象布局和符号修饰,但还有其他一些。

    缺乏来自标准的方向意味着编译器实现者会做一些不同的事情,这意味着很少有人有编写可移植反射库的动机,这意味着需要反射的人重新发明轮子,但是只够他们需要的。这发生在无限期,我们就在这里。

    【讨论】:

      【解决方案6】:

      也看了一会儿。当前最简单的解决方案似乎是BOOST_FUSION_ADAPT_STRUCT。实际上,一旦您有了库/头文件,您只需将结构字段添加到 BOOST_FUSION_ADAPT_STRUCT() 宏中,如the last segment of the code shows。是的,它有许多其他人提到的限制。而且它不直接支持听众。

      我研究过的其他有希望的解决方案是

      • CAMP 和 XRTTI/gccxml,但是两者似乎都是将外部工具依赖项引入项目的障碍。
      • 几年前,我使用 perl c2ph/pstruct 从 gcc -gstabs 的输出中转储元信息,虽然它对我来说非常有效,但需要更多的工作。

      关于 boost/__cxa 方法,一旦你弄清楚所有的小细节,添加/更改结构或字段就很容易维护。我们目前使用它在 dbus 之上构建自定义类型绑定层,以序列化 API 并隐藏托管对象服务子系统的传输/RPC 详细信息。

      【讨论】:

      • 这是否启用 /reflection/?我可以看到这如何调整结构来模拟 Boost MPL/Fusion 的序列概念,因此您可以迭代它的字段。但是,获取字段名称或使用名称访问字段是不可能的,IIRC。这甚至不涉及结构类型本身
      • @sehe:如您所见,字段类型由 __cxa_demangle(typeid(t).name()) 打印。相同的函数可以应用于结构解码器和数组解码器以打印所有结构类型和数组类型,包括最顶层。如果您认为 java vm 在内部二进制列表中保留了所有类/对象的列表,则此示例转储的元数据大致处于该级别。根据该低级信息(加上运行时地址信息),您需要编写代码来访问字段(按字符串或 char[] 格式的名称)。那将是整个反射画面的另一半。
      • 啊。因此,答案中最重要的部分实际上并不存在。嗯,这很令人惊讶。无论如何,我会+1 c2ph/pstruct。老派,但真的可以在大多数地方工作。 __cxa* 并不是完全可移植的。而且 ADAPT_STRUCT 不是很相关,易于使用,也不容易自动化。如果您正在使用宏,您不妨完全使用宏(而不依赖于 Boost 或 GCC ABI)
      • 实际上对我来说最重要的部分是运行时成本最低和侵入性最低的过程。 c2ph/pstruct 看起来不是很便携。我不得不花费大量精力来修复特定 gcc stabs 转储的 pstruct。在转储类型信息并从构建的二进制文件中检索地址信息后,只需要在运行时中构建一个内存访问接口。其他一切都可以开箱即用(我做嵌入式编程,主要使用反射进行测试)。因此,这个 ADAPT_STRUCT 是迄今为止我能找到的最简单的解决方案。
      • 刚刚重新红色sehe的最后一条评论:你做了两轮。第一轮在主机上编译/运行以使用 __cxa*/boost 转储元信息。第二轮以您在目标中定义的格式构建元信息。然后在目标构建中没有对 boost 或 g++ 的依赖。
      【解决方案7】:

      不是通用的,但 QT 通过元编译器支持这一点,并且是 GPL。 我与 QT 人员交谈的理解是,纯 C++ 无法做到这一点,因此需要 moc。

      【讨论】:

        【解决方案8】:

        自动内省/反思工具包。使用 Qt 之类的元编译器并将元信息直接添加到目标文件中。直观易用。没有外部依赖。甚至允许自动反映 std::string 然后在脚本中使用它。请访问IDK

        【讨论】:

        • 链接显示“您需要权限”,显然该站点已设置为私人访问。
        猜你喜欢
        • 2011-02-15
        • 2010-11-21
        • 1970-01-01
        • 2017-05-31
        • 1970-01-01
        • 2023-04-10
        • 2010-09-22
        • 2011-02-11
        • 1970-01-01
        相关资源
        最近更新 更多