注意事项:
根据 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> {};
似乎在做我想做的事(是吗?),但我不知道如何在我的程序中访问 Array<> 基本结构中的数据。 It also has other limitations noted by Stephen Lin below.
最佳答案
这不是一个完整的答案,但很难放入评论中。访问 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<...>
是否以书面形式正确利用此优化是另一回事。)
关于C++ 模板 : avoiding zero-length arrays without taking up extra space,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15183239/