一种C ++构造,它提高了可读性,评估为空而不是宏

时间:2015-02-12 11:10:35

标签: c++ templates readability api-design

我有以下情况。我们正在编写一个库,它有一个具有很多字段(大多数)的类,具体取决于一些可选字段,如果可选字段存在,则具有“flags”(基本上是数字中的位)。

该类的字段必须公开才能更容易访问(我知道它很糟糕),第三方开发人员将读取头文件(除了他们的文档)以熟悉结构和连接各种领域的相应选项。

问题是,客户希望他们的开发人员能够轻松地确定哪些字段取决于哪个可选结构尽可能少。

其中一个解决方案是在字段(类成员)名称之上或之后添加注释,告诉它使用此选项字段。这是基本选择。

然而,该课程已经超过500个成员(字段),所以我不知道如果添加额外500行,或长评论会增加它的质量。

我们想出了以下结构:

#define DEPENDS
#define ON
#define BIT(x) ((x)-1)
#define OF(x)

struct source{};

struct options 
{
    options(const source&) {}
};

template <int BITIDX>
struct optional
{
    optional(const options&) {}
};

struct something
{
    // this constructor will be implemented in the CPP
    // so the user  (developer) will not see it
    something (const source& src) :
      msource(src), initial_options(src), other_options(src), 
      field1(initial_options), field2(other_options) {}

    options initial_options;
    options other_options;

    optional<DEPENDS ON BIT(1) OF (initial_options)>   field1;
    optional<DEPENDS ON BIT(1) OF (other_options)  >   field2;

    source msource;
};

int main()
{
    source s;
    something a(s);
}

但是由于命名空间污染,宏等等,显然这并不是更好......

所以,问题是:有没有更好的方法来实现我们的目标,即提供一种有意义的方式来呈现一个选项的字段连接?

(请注意,C ++ 11类成员初始化是 NOT 允许,否则我不会问这个问题:)我们必须坚持使用较旧的编译器:()

1 个答案:

答案 0 :(得分:0)

struct something
{
    enum OptionGroup { Initial, Other /*...*/ };
    enum InitialFields { A, B /*...*/ };
    enum OtherFields { X, Y /*...*/ };

因此,我们列举了每个可选组中的字段A,B等。由于它们是从零开始并递增的,因此枚举值将告诉我们哪个位代表每个字段。

    template <typename TYPE, OptionGroup GROUP, int BIT>
    struct Optional {
        TYPE val;
        operator TYPE& () { return val; }
        operator TYPE const& () const { return val; }
    };

这将记录可选字段的组,该组中的哪个位表示它。你没有说明你的领域是什么类型,所以我把它变成了通用的。您也没有说明如何初始化它们,因此它可能需要构造函数等。

    int mandatory1;
    int initialOptions;
    Optional<int, Initial, A> a;
    Optional<int, Initial, B> b;
    int otherOptions;
    Optional<double, Other, X> x;

这里我们有一系列强制和可选字段的实际存储空间。

现在,我们需要一些方法来获取每个组的标志:

    template <OptionGroup GROUP> int getGroupFlags();

,我们可以检查给定字段是否有效......

    template <typename TYPE, OptionGroup GROUP, int BIT>
    bool isValid(Optional<TYPE,GROUP,BIT> const &field) {
        return getGroupFlags<GROUP>() & (1 << BIT);
    }
};

可悲的是,记录枚举和组之间的关联仍然是手动的(这是能够将两组选项标志合并到一个位字段中会使生活更轻松的地方)

template <> int something::getGroupFlags<something::Initial>() { return intialOptions; }
template <> int something::getGroupFlags<something::Other>() { return otherOptions; }

这可以大大清理(例如,通过将每个可选组绑定到单个结构中而不是硬编码令人讨厌的OptionGroup-&gt;标志字段关系),但这似乎是最不起作用的。