使用std::array声明二维(甚至更高维)数组的便捷方式

2023年 8月 20日 101点热度 1人点赞 0条评论

我准备将很多旧的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

admin

这个人很懒,什么都没留下