4

笔记:

根据liveworkspace.org的说法,这个问题的答案适用于 g++ (4.7.2)、clang (3.2) 和 icc (13.0.1) 的最新版本,但根据 Stephen Lin 的评论,这取决于空基优化和的实施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> {};

似乎做我想做的事(是吗?),但我不知道如何访问程序中 Array<> 基本结构中的数据。 它还具有以下 Stephen Lin 指出的其他限制。

4

1 回答 1

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>子对象ComboFour可能会或可能不会占用零空间,这称为“空基优化”,标准允许但不是必需的。)

可能有一些方法可以解决第二个问题......我认为继承std::tuple<...>(可能会或可能不会通过您的标准库实现在内部使用空基优化来实现)Array<T, N>,如果你这样做,可能是最简单的方法确实必须这样做,但这会使语法更加丑陋。

编辑:这适用于 GCC 4.7.2

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>>
{
};

然后...

Combo<int, 2, int, 2, float, 3> c;
std::get<0>(c).data[0] = 0;
std::get<0>(c).data[1] = 1;
std::get<1>(c).data[0] = 2;
std::get<1>(c).data[1] = 3;
std::get<2>(c).data[0] = 0.0;
std::get<2>(c).data[1] = 1.0;
std::get<2>(c).data[2] = 2.0;

assert(sizeof(Combo<int, 0, int, 0, float, 1>) == sizeof(float));

(老实说,标准库或多或少需要空基优化才能使用,所以即使它不是必需的,如果任何最近的编译器不支持它,我都会感到惊讶;无论是否std::tuple<...>以书面形式正确利用这一点优化是另一回事。)

于 2013-03-03T07:14:22.973 回答