我正在使用基于std::array
的二维数组。
基本上,与其使用:
MyType myarray[X_SIZE][Y_SIZE];
我有:
std::array<std::array<MyType, Y_SIZE>, X_SIZE> myarray;
这个代码运行良好,但我认为声明部分不是很易读。
有没有一种使用巧妙的C++模板机制来声明它的方法,使得声明看起来像这样?
My2DArray<Mytype, X_SIZE, Y_SIZE> myarray;
template <class T, std::size_t X, std::size_t Y>
using My2DArray = std::array<std::array<T, Y>, X>;
template <class T, std::size_t N, std::size_t... Ns>
struct AddArray {
using type = std::array<typename AddArray<T, Ns...>::type, N>;
};
template <class T, std::size_t N>
struct AddArray<T, N> {
using type = std::array<T, N>;
};
template <class T, std::size_t... N>
using MyNDArray = typename AddArray<T, N...>::type;
// Some namespace to hide the poorly-constrained template function:
namespace array_making {
template <std::size_t N>
struct array_dim {};
template <typename T, std::size_t N>
constexpr auto operator%(array_dim<N>, T const&)
-> std::array<T, N>;
}
template <typename T, std::size_t... Is>
using md_array_t = decltype(
(array_making::array_dim<Is>{} % ... % std::declval<T>())
);
md_array_t<int, 1, 2, 3>
是 array<array<array<int, 3>, 2>, 1>
。如果您喜欢相反的顺序,请反转operator%
的参数和折叠表达式的参数。
请注意,如果类型T
在关联命名空间中具有无约束的operator%
(请约束您的运算符!),则会遇到问题。我们可以通过选择不太可能的运算符(如.*
,->*
或%=
)或使用array_type<T>
包装器来减少发生此情况的风险。这两种解决方案都不能完全避免未适当约束T
的操作符重载问题。
MyNDArray
/ md_array_t
之一进行包装以获得另一种接口:template <typename Arr, std::size_t... Is>
constexpr auto make_array_impl(std::index_sequence<Is...>)
-> md_array_t<std::remove_all_extents_t<Arr>,
std::extent_v<Arr, Is>...>;
template <typename Arr>
using make_array = decltype(make_array_impl<Arr>(
std::make_index_sequence<std::rank_v<Arr>>{}));
这使得我们可以写make_array<int[4][5][6]>
来表示array<array<array<int, 6>, 5, 4>
。
说明:
std::rank
给出数组类型的维度数。因此,对于int[4][5][6]
,它返回3。make_index_sequence
以得到索引包。(0, 1, 2
)std::remove_all_extents
给出数组的基础类型;T[a][b]...[n]
-> T
(int
)std::extent
给出给定维度的大小。我们为每个索引调用这个函数(4, 5, 6
)。通过将这些传递给我们先前实现的md_array_t
,我们最终得到了md_array_t<int, 4, 5, 6>
,它产生了我们想要的结果。
[Y][X]
(并且在答案的模板中是std::array<std::array<T, X>, Y>
),因为通常我认为 X 是基本维度,它被连续迭代。当然,如果您主要通过 Y 进行迭代,则您的示例也是最优的,因此这取决于用途。 - Ped7gmyarray[x_index][y_index]
。 - Jabberwockyint map[4][3];
那么内存布局为[0][0], [0][1], [0][2], [1][0], [1][1], ...
,也就是第二维形成整块连续的整数,因此你应该(在可能的情况下)在内部循环中迭代第二维,在外部循环中迭代第一维。在你的维度中,这意味着将 X 作为外部循环,将 Y 作为内部循环(我的意思是对于那些甚至可以进行这种区分的情况,例如矩阵加法,在乘法中并不那么重要,因为两个矩阵中的一个必须以次优的顺序遍历),等等。 - Ped7g