We can alias a multidimensional array like this:
template<typename T, size_t size1, size_t size2>
using myArray = std::array<std::array<T, size2>, size1>;
But this only allows us a predefined number of dimensions. Is there a way to turn this into a variadic template, so that we could write any of those:
myArray<int, 2, 2, 2> arr3d;
myArray<int, 2, 2, 2, 2> arr4d;
I've tried a few things but wasn't completely satisfied with any of them.
This:
template<typename T, size_t size>
using myArray<T, size> = std::array<T, size>;
template<typename T, size_t size, size_t... more>
using myArray = std::array<myArray<T, more...>, size>;
doesn't even compile because template specializations are apparently not allowed with alias templates.
This is currently my best solution but deletes all constructors of std::array which I would like to keep:
template<typename T, size_t size, size_t... more>
struct myArray : public std::array<myArray<T, more...>, size> {};
template<typename T, size_t size>
struct myArray<T, size> : public std::array<T, size>{};
And with this solution I would always have to write ".internal" in front of every array access:
template<typename T, size_t size, size_t... more>
struct myArr {
std::array<myArr<T, more...>, size> internal;
};
template<typename T, size_t size>
struct myArr<T, size> {
std::array<T, size> internal;
};
So could anyone think of a solution like the second but where I could keep the constructors? I can't.
I would suggest simply multiplying the dimensions together and having a single std::array
. E.g.: std::array<int, D0 * D1 * D2 * D3>
. You can then provide utility functions or a wrapper class to convert a multi-dimensional index into one-dimensional.
Anyway...
Here's a simple recursive solution that uses explicit template specialization:
template <typename T, std::size_t... Ds>
struct nested_array;
template <typename T, std::size_t D>
struct nested_array<T, D>
{
using type = std::array<T, D>;
};
template <typename T, std::size_t D, std::size_t... Ds>
struct nested_array<T, D, Ds...>
{
using type = std::array<typename nested_array<T, Ds...>::type, D>;
};
static_assert(std::is_same_v<
typename nested_array<int, 1, 2, 3>::type,
std::array<std::array<std::array<int, 3>, 2>, 1>
>);
live example on wandbox
Here's a solution based on variable template partial specialization:
template <typename T>
struct t { using type = T; };
template <typename T>
using unwrap = typename T::type;
template <typename T, std::size_t... Ds>
constexpr auto nested_array = t<void>{};
template <typename T, std::size_t D>
constexpr auto nested_array<T, D> = t<std::array<T, D>>{};
template <typename T, std::size_t D, std::size_t... Ds>
constexpr auto nested_array<T, D, Ds...> =
t<std::array<unwrap<decltype(nested_array<T, Ds...>)>, D>>{};
static_assert(std::is_same_v<
unwrap<decltype(nested_array<int, 1, 2, 3>)>,
std::array<std::array<std::array<int, 3>, 2>, 1>
>);
live example on wandbox
You might use extra layer:
template<typename T, size_t size, size_t... more>
struct myArray_impl
{
using type = std::array<typename myArray_impl<T, more...>::type, size>;
};
template<typename T, size_t size>
struct myArray_impl<T, size>
{
using type = std::array<T, size>;
};
template<typename T, size_t size, size_t... more>
using myArray = typename myArray_impl<T, size, more...>::type;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With