在编译时动态生成结构

时间:2012-07-07 15:15:34

标签: c++ templates c++11 structure template-meta-programming

我必须生成一个仅在某些条件下包含某些字段的数据结构。这通常会转换为类似以下内容的

struct MyStruct {
    int     alwaysHere;

#ifdef WHATEVER
    bool    mightBeHere;
#endif

    char    somethingElse;

#if SOME_CONSTANT > SOME_VALUE
    uint8_t alywasHereButDifferentSize;
#else
    uint16_t alywasHereButDifferentSize;
#endif
...
};

从我的观点来看,这看起来很难看,而且难以理解。 甚至没有谈论处理这些字段的代码,通常是在 ifdef也是。

我正在寻找一种优雅的方法来实现相同的结果,而不会增加任何开销,但代码很多 更具可读性。模板专业化似乎有点过分,但在我看来 成为唯一的选择。

C ++ 11是否会添加任何内容来处理这种情况?

任何建议都将不胜感激。

4 个答案:

答案 0 :(得分:5)

对于第二种情况,我通常更喜欢将hackery限制在一个地方的typedef:

#if SOME_CONSTANT > SOME_VALUE
    typedef uint8_t always_type;
#else
    typedef uint16_t always_type;
#endif

然后,您的其余代码将始终使用always_type

struct MyStruct {
    // ...
    always_type always_here_but_different_size;
    // ...
};

如果您想使用:

typedef std::conditional<(SOME_CONSTANT > VALUE), uint8_t, uint16_t>::type always_type;

那也没关系 - 这里的重点不是你用来获得你想要的类型的语法,而是你通常想为这个类型创建一个名字,这样你就可以在需要时使用它。

至于某事物是否存在的情况,很难说是 little 。通常,这样的事情将涉及在构建时启用/禁用某些功能。如果是这样,那么该类似乎具有与可以启用/禁用的功能相关的职责,以及与其他功能相关的职责。这听起来似乎违反了单一责任原则,可能不是很有凝聚力。如果是这种情况,它可能表明在整体设计层面上更好地解决的问题,而不仅仅是您使用的语法。

警告:我可能从公认的最小证据中推断出相当多的证据 - 可能超过证据确实支持的证据。

答案 1 :(得分:4)

第二种情况可以替换为

std::conditional<(SOME_CONSTANT > SOME_VALUE), uint8_t, uint16_t>::type
alywasHereButDifferentSize;

首先我认为没有。

答案 2 :(得分:1)

我已经看到这样做了一个工会(http://www.cplusplus.com/doc/tutorial/other_data_types/),但我不确定具体细节,因为我自己从未实现过。你将拥有:

而不是第二块宏观困境
union {
  uint8_t alywasHereButDifferentSize;
  uint16_t alywasHereButDifferentSize;
}

并且在引用时,你会得到一个if引用一个或另一个变量。

或者,您可以创建一个void *指针,在运行时将其初始化为任一类型的变量。

答案 3 :(得分:0)

第一个:

template <bool>
struct implement_maybe_here
{};

template <>
struct implement_maybe_here<true>
{
    int maybe_here;
};

struct my_struct : implement_maybe_here<HAS_MAYBE_HERE>
{
    double always_here;
};

我不建议这样做,因为它很难维护,并且maybe_here变量很难初始化(但无论如何,无论如何,这将是一个烂摊子。)

请注意,您不能保证implement_maybe_here<false>将占用零内存,但是许多编译器会实现此“empty base optimization”。

使用std::conditional作为第二个,正如@ForEveR建议的那样。