Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

multi-dimensional array initialization based on std::array

Tags:

c++

After seeing the benefits of std::array I was trying to create a class that supports multiple dimensions.

My initial experiments used nested std::array. I chose not to use this method partly for the ugly way to write the type.

ie: std::array<std::array<std::array<...>, >, >

The new class is mostly working except for initialization. I haven't decided whether its best to use inheritance or containment. The choice may depend on whether I can get initialization working.

How can I get either of the last two lines of this to compile:

// multi-dimensional array based on std::array

#include <array>

template <class T, int s, int... r>
class arraynd_a : public std::array<arraynd_a<T, r...>, s>
{
public:
};

template <class T, int s>
class arraynd_a<T, s> : public std::array<T, s>
{
public:
};

template <class T, int s, int... r>
class arraynd_b
{
public:
    std::array<arraynd_b<T, r...>, s> arr;
};

template <class T, int s>
class arraynd_b<T, s>
{
public:
    std::array<T, s> arr;
};

void test()
{
    constexpr std::array<std::array<int, 2>, 3> a1 = { { { 0, 1 }, { 1, 0 }, { 2, 4 } } };
    /*constexpr*/ arraynd_a<int, 3, 2> a2a;
    /*constexpr*/ arraynd_b<int, 3, 2> a2b;
#if 0
    /*constexpr*/ arraynd_a<int, 3, 2> a3a =  { { { 0, 1 }, { 1, 0 }, { 2, 4 } } };
#endif
#if 0
    /*constexpr*/ arraynd_b<int, 3, 2> a3b =  { { { 0, 1 }, { 1, 0 }, { 2, 4 } } };
#endif
}
like image 858
RadAd Avatar asked Dec 11 '25 11:12

RadAd


1 Answers

If you are doing the member class way, you have to wrape the array content one more time with {} (you also do not initialize an array with std::array<int, 2> arr = 1, 2;, or?):

template <class T, std::size_t DIM, std::size_t... ARGS>
struct arr_mult_dim
{
    std::array<arr_mult_dim<T, ARGS...>, DIM> arr_;
};
template <class T, int DIM>
struct arr_mult_dim<T, DIM>
{
    std::array<T, DIM> arr_;
};
template <class T, std::size_t... DIMS>
using arr_mult_dim_t = arr_mult_dim<T, DIMS...>;

And use it like that:

arr_mult_dim_t<int, 2> arr_1 = { { 0, 1 } };

But a more pretty way to do it would be if you generate the needed type with a nested using declaration:

template <class T, std::size_t DIM, std::size_t... ARGS>
struct arr_mult_dim
{
    using type = std::array<typename arr_mult_dim<T, ARGS...>::type, DIM>;
};
template <class T, std::size_t DIM>
struct arr_mult_dim<T, DIM>
{
    using type = std::array<T, DIM>;
};
template <class T, std::size_t... DIMS>
using arr_mult_dim_t = typename arr_mult_dim<T, DIMS...>::type;

The usage would be:

arr_mult_dim_t<int, 2> arr_1 = { 0, 1 };
arr_mult_dim_t<int, 2, 2> arr_2 = { { { 0, 1 }, {0, 1} } };
arr_mult_dim_t<int, 2, 2, 2> arr_3 =
{
    {
        {
            {
                {0, 1 },
                { 0, 1 }
            }
        },
        {
            {
                { 0, 1 },
                { 0, 1 }
            }
        }
    }
};

Now you don't need to use the extra {}.

EDIT: I did some research. I don't know why your inheritation solution isn't working. The class which inherites from a class with aggregate propierties should also have aggregate propiertes. The standard says:

The elements of an aggregate are: ...
- for a class, the direct base classes in declaration order followed by the direct non-static data members
in declaration order.

Looks like this isn't implemented yet. In older standards there is a clausel which is explicitly prohibiting aggregate classes to have base classes: Why can I not brace initialize a struct derived from another struct?

like image 169
JulianH Avatar answered Dec 13 '25 01:12

JulianH



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!