Jab*_*cky 42 c++ arrays multidimensional-array stdarray
我即将将大量旧的 C++ 代码转换为更现代的 C++。
该代码中有许多原始的二维数组,例如:
Foo bar[XSIZE][YSIZE];
Run Code Online (Sandbox Code Playgroud)
我即将用以下内容替换这些声明
std::array<std::array<Foo, YSIZE>, XSIZE> bar;
Run Code Online (Sandbox Code Playgroud)
这是一种方便的方法,因为语句保持不变,并且代码的行为应该与原始数组相同,并且具有能够在调试版本中进行越界检查的额外好处。
但在我看来,这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;
Run Code Online (Sandbox Code Playgroud)
但我觉得这是一个宏黑客,我想知道是否有一种更干净、更 C++ 的方法来做类似的事情。
Ayx*_*xan 76
您可以使用类型别名模板:
#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;
}
Run Code Online (Sandbox Code Playgroud)
您还可以将其推广到任何维度:
#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;
}
Run Code Online (Sandbox Code Playgroud)
Yak*_*ont 24
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>;
};
Run Code Online (Sandbox Code Playgroud)
现在
array_t<Foo[XSIZE][YSIZE]>
Run Code Online (Sandbox Code Playgroud)
是
std::array< std::array<Foo, XSIZE>, YSIZE>
Run Code Online (Sandbox Code Playgroud)
另一种解决方案是:
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>;
};
Run Code Online (Sandbox Code Playgroud)
这使用语法:
array_t<Foo, XSIZE, YSIZE>
Run Code Online (Sandbox Code Playgroud)
如果你喜欢的话。
我们甚至可以将两者结合起来,允许任一语法。
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_t<T, Ns...>, N0>
{};
Run Code Online (Sandbox Code Playgroud)
现在
array_t< Foo[XSIZE], YSIZE >
Run Code Online (Sandbox Code Playgroud)
作品。
但要小心——顺序很棘手!
int[3][2] is an array of 3 elements of arrays of 2 elements.
Run Code Online (Sandbox Code Playgroud)
为了保持我们想要的不变
array_t<int, 3, 2>
Run Code Online (Sandbox Code Playgroud)
成为
std::array< std::array< int, 2 >, 3>
Run Code Online (Sandbox Code Playgroud)
不是
std::array< std::array< int, 3 >, 2>
Run Code Online (Sandbox Code Playgroud)
以下是确定您的顺序是否正确的测试用例:
static_assert( std::is_same_v< std::array<int, 3>, array_t<int, 3> > );
static_assert( std::is_same_v< std::array< std::array<int, 2>, 3>, array_t<int, 3, 2> > );
static_assert( std::is_same_v< std::array< std::array<int, 2>, 3>, array_t<int[3], 2> > );
static_assert( std::is_same_v< std::array< std::array<int, 2>, 3>, array_t<int[3][2]> > );
Run Code Online (Sandbox Code Playgroud)
删除与您选择的语法错误的内容array_t。
现在,即使这样也可能是错误的。感觉不正确的是
array_t<int[3], 2>
Run Code Online (Sandbox Code Playgroud)
还没有大小为 3 的子数组
array_t<int[3][2]>
Run Code Online (Sandbox Code Playgroud)
感觉应该也是同一个数组,而且 的布局int[3][2]应该和array_t<int[3][2]>一致array_t<int, 3, 2>。
另外,array_t< array_t<int, 3>, 2>应该与 相同array_t<int[3], 2>。
这些要求彼此不一致。我的意思是,他们在所有地方都不同意。
解决此问题的最简单方法可能是仅需要[][][]语法,或者不允许混合[]语法,。
具有array_t<int[3][2]>相同的布局int[3][2]是高价值的。同样,拥有array_t< int, 3, 2 >语法也具有很高的价值。可能我们想表达的意思与?array_t<int, 3, 2>相同。int[3][2]丢弃这个等于array_t< array_t<int, 3>, 2>- 相反,它等于array_t<array_t<int,2>,3>。最后,块array_t<int[3], 2>语法令人困惑。
然后,拆分array_t< T, 1,2,3,...>模板array_t<T[1][2][3]...>以最大程度地减少混乱。
在 C++23 中,您可以使用获取一维数组的std::mdspan多维视图。有一个关于 a 的提案std::mdarray,但至少要到 C++26 才会出现在 C++ 中。
std::mdspan如何使用的示例:
std::array<Foo, XSIZE * YSIZE> bar_1d;\nstd::mdspan bar(bar_1d.data(), XSIZE, YSIZE);\n\xe2\x80\xa6\nfor (std::size_t y = 0; y != YSIZE; ++y) {\n for (std::size_t x = 0; x != XSIZE; ++x) {\n std::cout << bar[x, y] << \' \';\n }\n std::cout << \'\\n\';\n} \nRun Code Online (Sandbox Code Playgroud)\n