我准备将很多旧的C++代码转换为更现代的C++。
代码中有许多像这样的原始二维数组:
Foo bar[XSIZE][YSIZE];
我打算将这些声明替换为:
std::array<std::array<Foo, YSIZE>, XSIZE> bar;
这是一种方便的方式,因为语句保持不变,代码应该与使用原始数组时的行为相同,而且还能够在调试构建中进行越界检查。
但是在我看来,std::array<std::array<Foo, YSIZE>>
有些繁琐,不易阅读,而且对于3D数组(尽管我没有)来说,情况会更糟。
目前我正在使用这个宏使声明更易读:
#define DECLARE_2D_ARRAY(type, x, y) std::array<std::array<type, y>, x>
...
DECLARE_2D_ARRAY(Foo, XSIZE, YSIZE) bar;
但我觉得这是一种宏技巧,我想知道是否有一种更清晰、更符合C++的方式来做类似的事情。
回答1
你可以使用类型别名模板:
#include <array>
#include <cstddef>
template <class T, std::size_t x, std::size_t y>
using Array2D = std::array<std::array<T, y>, x>;
int main() {
Array2D<int, 5, 3> arr;
}
你还可以像这样对任何维度进行泛化:
#include <array>
#include <cstddef>
template <class T, std::size_t size, std::size_t... sizes>
struct ArrayHelper {
using type = std::array<typename ArrayHelper<T, sizes...>::type, size>;
};
template <class T, std::size_t size>
struct ArrayHelper<T, size> {
using type = std::array<T, size>;
};
template <class T, std::size_t... sizes>
using Array = typename ArrayHelper<T, sizes...>::type;
int main() {
Array<int, 5, 3, 4, 3> arr;
}
回答2
template<class A>
struct std_array_helper {
using type=A;
};
template<class A>
using array_t = typename std_array_helper<A>::type;
template<class T, std::size_t N0>
struct std_array_helper<T[N0]> {
using type=std::array<array_t<T>, N0>;
};
现在
array_t<Foo[XSIZE][YSIZE]>
等同于
std::array< std::array<Foo, XSIZE>, YSIZE>
另一种替代方案是:
template<class T, std::size_t...Sz>
struct array_helper {
using type=T;
};
template<class T0, std::size_t...Ns>
using array_t = typename array_helper<T0, Ns...>::type;
template<class T, std::size_t N0, std::size_t...Ns>
struct array_helper<T, N0, Ns...>
{
using type=std::array<array_t<T, Ns...>, N0>;
};
这使用了语法:
array_t<Foo, XSIZE, YSIZE>
如果你更喜欢这个语法。
甚至可以将两者结合起来,允许使用任一种语法。
template<class T, std::size_t...Sz>
struct array_helper {
using type=T;
};
template<class T0, std::size_t...Ns>
using array_t = typename array_helper<T0, Ns...>::type;
template<class T, std::size_t N0, std::size_t...Ns>
requires (!std::is_array_v<T>)
struct array_helper<T, N0, Ns...>
{
using type = std::array<array_t<T, Ns...>, N0>;
};
template<class T, std::size_t N0, std::size_t...Ns>
struct array_helper<T[N0], Ns...>:
array_helper<array