是的,原则上这应该是可能的。这里有一些帮助您入门:
template <class T, std::size_t... Dim>
using VariableLengthTable = std::tuple<std::array<T, Dim>...>;
这是std::arrays 的元组,每个元组的长度由模板参数之一指定。
请注意,因为 std::array 的长度是其类型的一部分,所以第一个维度不能是数组,因为它的成员需要不同的类型。但是,std::tuple 工作得很好。只要你愿意使用std::get<i>而不是[i],并且将自己限制在编译时is,你就可以了。
如果编译时i 不够用,您有两种选择:
一个,如上使用VariableLengthTable并添加运行时到编译时的转换。从概念上讲,类似switch:
T& get(std::size_t x, std::size_t y)
{
switch (x) {
case 0: return std::get<0>(varLenTable)[y];
case 1: return std::get<1>(varLenTable)[y];
case 2: return std::get<2>(varLenTable)[y];
// and so on
}
}
实际上,您可能需要使用递归或继承来组合它,以避免编译时越界访问。 Boost.Preprocessor 可能会对此有所帮助。
二,将所有数据存储在一个顺序缓冲区中,并在运行时对其进行索引。像这样的:
template <class T, std::size_t... Dim>
class VariableLengthTable
{
static const std::array<std::size_t, sizeof...(Dim)> dims = {{ Dim... }};
static const std::array<std::size_t, sizeof...(Dim)> cumulDims = [](){
std::array<std::size_t, sizeof...(Dim)> result;
result[0] = 0;
for (std::size_t idx = 1; idx < sizeof...(Dim); ++idx) {
result[idx] = result[idx - 1] + dims[idx];
}
return result;
}();
std::array<T, cumulDims[sizeof...(Dim) - 1] + dims[sizeof...(Dim) - 1]> data;
public:
T& get(std::size_t x, std::size_t y)
{
return data[cumulDims[x] + y];
}
};
上面的代码是为了说明原理,不保证按原样编译。