一个C++结构,它可以提高可读性,计算结果为零,但不是宏

A C++ construct which improves readability, evaluates to nothing but is NOT a macro

本文关键字:结果 计算 结构 C++ 一个 可读性      更新时间:2023-10-16

我有以下情况。我们正在编写一个库,它有一个类,它有很多字段(大部分),这取决于一些可选字段,如果可选字段存在与否,这些字段都有"标志"(基本上是数字中的位)。

类的字段必须是公共的,以便于访问(我知道这很糟糕),第三方开发人员将阅读头文件(除了他们的文档),以便熟悉各种字段的结构和与相应选项的连接。

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

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

然而,这个类已经有大约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允许的,否则我不会问这个问题:)我们必须坚持使用较旧的编译器:()

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->flag字段关系进行硬编码),但这似乎是最少的工作。