c ++模板:避免零长度数组而不占用额外空间

时间:2013-03-03 06:55:07

标签: c++ templates

注意:

根据liveworkspace.org,对于g ++(4.7.2),clang(3.2)和icc(13.0.1)的最新版本,这个问题的答案是有效的,但根据Stephen Lin的评论,它取决于empty base optimization以及std::tuple的实施。


最初的问题:

如果我有一个如下所示的模板结构:

template<
    class T1, unsigned short N1,
    class T2, unsigned short N2
>
struct ComboThree {
    T1 data_1[N1];
    T2 data_2[N2];
};

我可以通过专门化来避免零长度数组和额外的对齐填充:

template<class T1, class T2>
struct ComboThree<T1, 0, T2, 0> {
};

template<class T1, class T2, unsigned short N2>
struct ComboThree<T1, 0, T2, N2>
{
    T2 data_2[N2];
};

template<class T1, unsigned short N1, class T2>
struct ComboThree<T1, N1, T2, 0>
{
    T1 data_1[N1];
};

但是当TX / NX对的X变得更大时,像这样的专业化变得麻烦。在我的项目中,不同组合的实际数量可能会少于五个,所以我最终可能根本不使用模板,但我很好奇:

有没有办法使用TEMPLATE MAGIC来避免零长度数组,同时避免占用任何额外空间?

例如,这个:

template<class T, unsigned short N>
struct Array {
    T data[N];
};

template<class T>
struct Array<T, 0> {};

template<
    class T1, unsigned short N1,
    class T2, unsigned short N2
>
struct ComboTwo {
    Array<T1, N1> data_1;
    Array<T2, N2> data_2;
};

避免了零长度数组,但空结构占用了额外的空间。另一方面,这个:

template<class T, unsigned short N>
struct Array {
    T data[N];
};

template<class T>
struct Array<T, 0> {};

template<
    class T1, unsigned short N1,
    class T2, unsigned short N2
>
struct ComboFour : Array<T1, N1>, Array<T2, N2> {};

似乎做了我想做的事(是吗?),但我不知道如何访问数组中的数据&lt;&gt;基础结构在我的程序中。 It also has other limitations noted by Stephen Lin below.

1 个答案:

答案 0 :(得分:2)

这不是一个完整的答案,但很难适应评论。要访问ComboFour的子对象,如果您真的想要做最后一个选项,则需要以下丑陋的语法:

ComboFour<int, 2, float, 1> cf;
cf.Array<int, 2>::data[0] = 0;
cf.Array<int, 2>::data[1] = 1;
cf.Array<float, 1>::data[0] = 2.0f;

您可以使用一些访问器功能来清理它,但它仍然不会很好。

但更大的问题是,以下是一个错误:

ComboFour<int, 1, int, 1> cf2 // fails to compile

因为同一个班级不能两次用作父母。

(另请注意,Array<T, 0>的{​​{1}}个子对象可能会占用零空间,也可能不会占用零空间,这称为“空基本优化”,并且标准允许但不是必需的。)< / p>

可能有一些方法可以解决第二个问题......我认为继承ComboFour {可能会或可能不会使用标准库实现的内部空基础优化来实现} {{1}如果你真的不得不这样做,可能是最简单的方法,但它会使语法变得更加丑陋。

编辑:这适用于GCC 4.7.2

std::tuple<...>

以后......

Array<T, N>

(老实说,标准库或多或少需要空基优化才能使用,所以即使不需要它我也会感到惊讶,如果最近的编译器不支持它;是否template< class T1, unsigned short N1, class T2, unsigned short N2, class T3, unsigned short N3 > struct Combo : std::tuple<Array<T1, N1>, Array<T2, N2>, Array<T3, N3>> { }; 在书面上正确地利用这种优化是另一回事。)