如何设计一个带有“注释”字段的类?

2024-03-06

想象一下,我们有某种包含数百种消息类型的协议,我们希望通过 C++ 类对每种消息类型进行建模。由于每个类应该能够自动处理每个字段,一个自然的解决方案是只拥有一个std::tuple具有所有必需的类型:

std::tuple<int, double, char> message;

print(message);   // the usual variadic magic

这一切都很好。但是,现在我想给每个字段一个名称,并且我希望能够在代码中引用该字段时使用该名称,并获取它的文本表示形式。天真地,或者用 C 语言,我可能会这样写:

struct Message
{
    int    header;
    double temperature;
    char   flag;
};

这样我们就失去了元组的递归自动处理能力,但我们可以按字面意思命名每个字段。在 C++ 中,我们可以通过枚举来完成这两件事:

struct Message
{
    enum FieldID { header, temperature, flag };
    static const char * FieldNames[] = { "header", "temperature", "flag" };

    typedef std::tuple<int, double, char> tuple_type;

    template <FieldID I>
    typename std::tuple_element<I, tuple_type>::type & get()
    { return std::get<I>(data); }

    template <FieldID I>
    static const char * name() { return FieldNames[I]; }

    tuple_type data;
};

现在我可以说,Message m; m.get<Message::header>() = 12;等等,我可以递归这些字段,让每个字段打印出自己的值,并以自己的名称为前缀,等等。

现在的问题是:如何有效地编写这样的代码而不重复?

理想情况下,我希望能够这样说:

START_MESSAGE(Message)
ADDFIELD(int, header)
ADDFIELD(double, temperature)
ADDFIELD(char, flag)
END_MESSAGE

有没有办法结合预处理器、Boost 和 C++11 来实现这样的目标,而不需要外部生成工具? (我认为 Boost.Preprocessor 称之为“水平”和“垂直”重复。我需要以某种方式“转置”字段数据。)这里的关键特征是我永远不必重复任何信息,并且修改或添加一个字段只需要进行一次更改。


您可以使用 boost 的预处理器序列来做到这一点。

#define CREATE_MESSAGE(NAME, SEQ) ...

CREATE_MESSAGE(SomeMessage,
  (int)(header)
  (double)(temperature)
  (char)(flag)
)

您需要迭代每一对来生成定义。我没有任何方便的示例代码,但如果有趣的话我可能可以安排一些。

有一次,我有一个类似这样的生成器,它还生成了字段的所有序列化。我感觉有点太过分了。我觉得具体的定义和现场的声明性访问者更加直接。如果其他人必须在我之后维护代码,那就有点不那么神奇了。我不知道你的具体情况,刚实施后我还是有所保留。 :)

再次查看 C++11 功能会很酷,尽管我还没有机会。

Update:

虽然还有一些问题需要解决,但这基本上是有效的。

#include <boost/preprocessor.hpp>
#include <boost/preprocessor/seq/for_each_i.hpp>
#include <boost/preprocessor/arithmetic/mod.hpp>
#include <boost/preprocessor/control/if.hpp>

#include <tuple>

#define PRIV_CR_FIELDS(r, data, i, elem) \
    BOOST_PP_IF(BOOST_PP_MOD(i, 2),elem BOOST_PP_COMMA,BOOST_PP_EMPTY)()

#define PRIV_CR_STRINGS(r, data, i, elem) \
    BOOST_PP_IF(BOOST_PP_MOD(i, 2),BOOST_PP_STRINGIZE(elem) BOOST_PP_COMMA,BOOST_P

#define PRIV_CR_TYPES(r, data, i, elem) \
    BOOST_PP_IF(BOOST_PP_MOD(i, 2),BOOST_PP_EMPTY,elem BOOST_PP_COMMA)()

#define CREATE_MESSAGE(NAME, SEQ) \
    struct NAME { \
        enum FieldID { \
            BOOST_PP_SEQ_FOR_EACH_I(PRIV_CR_FIELDS, _, SEQ) \
        }; \
        std::tuple< \
            BOOST_PP_SEQ_FOR_EACH_I(PRIV_CR_TYPES, _, SEQ) \
        > data;\
        template <FieldID I> \
            auto get() -> decltype(std::get<I>(data)) { \
                return std::get<I>(data); \
            } \
        template <FieldID I> \
            static const char * name() { \
                static constexpr char *FieldNames[] = { \
                    BOOST_PP_SEQ_FOR_EACH_I(PRIV_CR_STRINGS, _, SEQ) \
                }; \
                return FieldNames[I]; \
            } \
    };

CREATE_MESSAGE(foo,
        (int)(a)
        (float)(b)
    )

#undef CREATE_MESSAGE

int main(int argc, char ** argv) {

    foo f;
    f.get<foo::a>() = 12;

    return 0;
}

get 的 decltype 有问题。我还没有真正使用过元组来知道那里会发生什么。不过,我认为这与生成类型或字段的方式没有任何关系。

以下是预处理器使用 -E 生成的内容:

struct foo { 
  enum FieldID { a , b , }; 
  std::tuple< int , float , > data;
  template <FieldID I> 
    auto get() -> decltype(std::get<I>(data)) { 
      return std::get<I>(data); 
  } 
  template <FieldID I> static const char * name() { 
    static constexpr char *FieldNames[] = { "a" , "b" , }; 
    return FieldNames[I]; 
  } 
};
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何设计一个带有“注释”字段的类? 的相关文章

随机推荐

  • django HttpResponse 和 unicode

    我使用 django 作为网络应用程序的后端 我通过 django 发送 json 数据 效果很好 然而最近我开始处理非 ASCII 数据并注意到非 ASCII 字符的一些异常行为 在我的网络应用程序中 我的代码如下所示 def make
  • 进行立即变量赋值

    我在使用 与使用 分配的变量相结合的 make 文件中立即分配变量时遇到问题 例如 VAR a VARS VAR rule1 echo VARS VAR b VARS VAR rule2 echo VARS 当我运行 make 时 无论规则
  • 动态类定义的酸洗

    我正在尝试将动态生成的类作为替代类的工厂 像下面这样 import sys pickle class BC object pass C type NewClassName BC pickle dump C sys stdout 这会导致以下
  • 谷歌地图 V3 JS 没有发生 UIWebView iOS 6(iPhone) 的“中心更改”

    我正在尝试显示GoogleMap Google maps V3 JS in UIWebView ios6 but 当我在网络视图中移动地图时 事件没有发生center changed 移动地图已完成 事件火 Why 有人告诉我页面 http
  • PHP使用时区函数的时差?

    我试图找到一种方法来使用 PHP 中的时区函数显示两个位置之间的时间差异 http php net manual en timezones php http php net manual en timezones php 假设我从上面的链接
  • Excel VBA - 运行时错误“9”,下标超出范围

    我真的很感谢我能得到的任何帮助 我试图循环遍历一列 查找重复的名称 然后从同一行获取该名称和其他几个数据 并将它们放入一个我想使用另一个函数的二维数组中 但它不起作用 我真的需要你的帮助来弄清楚为什么我不能在不保留数据的情况下重新调整这个数
  • Web 音频 API - 如何将音频缓冲区保存到包含所有更改的文件?

    我对音频缓冲区 例如增益和平移 进行了更改 并将它们连接到音频上下文 现在我想将所有已实施的更改保存到一个文件中 按原样保存缓冲区将为我提供未经更改的原始音频 有任何方法或程序可以做到这一点吗 方法是使用MediaRecorder保存修改后
  • java中继承私有字段

    如果子类不能从超类继承私有成员 但它从超类继承公共方法 这些方法可以访问未继承的私有成员 如此处所述 http docs oracle com javase tutorial java IandI subclasses html http
  • 无法找到 Microsoft 认知服务的订阅密钥

    I need to work on Microsoft Cognitive Services Face API I downloaded the code from https github com Microsoft Cognitive
  • CLARION 日期转换 C# + 日期加/减

    这是针对 ISV 数据库的 所以我对此进行了逆向工程并且无法更改 我如何在 C 中执行以下日期到 int visa versa 转换 所以说日期是 5 17 2012 它被转换为 int 77207 在数据库中 起初我以为这是儒略日期 但事
  • => 和 () => 在 Scala 中意味着什么[重复]

    这个问题在这里已经有答案了 我是 Scala 的新手 我真的很喜欢它 但有时它会让我感到惊讶 例如 clickedCallbacks List gt Unit 谁能告诉我什么 gt and gt 在斯卡拉中是什么意思 gt 是用于创建函数实
  • C# 和 SQL Server 中 int 到 guid 的不同转换

    在 C 和 SQL Server 中将 int 转换为 guid 时 我得到不同的值 在C 中我使用这个方法 public static Guid Int2Guid int value byte bytes new byte 16 BitC
  • Ant 无法删除 Windows 上的某些文件

    我有一个 ant 构建 可以创建目录 调用 javac 和所有常规内容 我遇到的问题是 当我尝试执行清理 删除生成的所有内容 时 删除任务报告无法删除某些文件 当我尝试手动删除它们时 效果很好 这些文件显然没有被任何其他进程打开 但 ant
  • 使用 CALayer 委托

    我有一个 UIView 其图层将有子图层 我想为每个子图层分配委托 因此委托方法可以告诉图层要绘制什么 我的问题是 作为 CALayer 的代表我应该提供什么 文档说不要使用图层所在的 UIView 因为这是为视图的主 CALayer 保留
  • 自定义控件中的选择器

    我正在建立一些表格 使用TableView 并注意到我对单元格的样式设置相同 我决定将这段重复的代码重构为一个公共控件 I am struggling to get the binding to work on the picker cor
  • 如何暂停在终端中运行的Python脚本

    我有一个网络爬行 python 脚本在终端中运行了几个小时 它不断填充我的数据库 它有几个嵌套的 for 循环 由于某些原因 我需要重新启动计算机并从我离开的位置继续执行脚本 是否可以保留指针状态并恢复之前在终端中运行的脚本 我正在寻找一种
  • ShellExecute 对于本地 html 或文件 URL 失败

    我们公司正在将我们的帮助系统迁移到 Flare 下的 HTML5 格式 我们还在 URI 命令行上使用 Flare CSHID 添加了对帮助系统的基于主题的访问 以便直接访问主题 例如index html CSHID GettingStar
  • MVC中如何定义img src路径

    我的 index cshtml 带有图像 里面还有一个Images文件夹myApp Images folder 如果我访问 http localhost myApp 或 http localhost myApp home 工作正常 但如果我
  • gcc 是否会根据条件优化我的循环?

    我有以下循环 condition will be set here to true or false for int i 0 i lt LARGE NUMBER i if condition do foo else do bar 假设 无条
  • 如何设计一个带有“注释”字段的类?

    想象一下 我们有某种包含数百种消息类型的协议 我们希望通过 C 类对每种消息类型进行建模 由于每个类应该能够自动处理每个字段 一个自然的解决方案是只拥有一个std tuple具有所有必需的类型 std tuple