基于std :: array的多维数组初始化

时间:2018-09-13 07:57:05

标签: c++

看到std :: array的好处后,我试图创建一个支持多维的类。

我最初的实验使用嵌套的std :: array。我选择不部分使用此方法来编写类型的丑陋方式。

即:std::array<std::array<std::array<...>, >, >

除了初始化外,新类主要在工作。我还没有决定是否最好使用继承或包含。该选择可能取决于我是否可以使初始化工作。

如何获取其中的最后两行之一:

// 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
}

2 个答案:

答案 0 :(得分:1)

如果您使用成员类方式,则必须用{}再包装一次数组内容(您也不要用std::array<int, 2> arr = 1, 2;来初始化数组,或者?):

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...>;

并像这样使用它:

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

但是,执行此操作的一种更漂亮的方法是使用嵌套的using声明生成所需的类型:

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;

用法为:

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 }
            }
        }
    }
};

现在,您无需使用多余的{}。

编辑:我做了一些研究。我不知道您的继承解决方案为什么不起作用。从具有综合属性的类继承的类也应具有综合属性。该标准说: 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. 似乎尚未实现。因为在较早的标准中,有一个子句明确禁止聚合类具有基类:Why can I not brace initialize a struct derived from another struct?

答案 1 :(得分:0)

我能够保留我的原始设计,并通过本机多维数组对其进行初始化:

#include <array>

template <class T, size_t s, size_t...r>
struct arraynd
{
    typedef arraynd<T, r...> inner_type;
    typedef typename inner_type::native_type native_type[s];

    static constexpr std::array<inner_type, s> to_arraynd(const native_type& init)
    {
        return impl_to_arraynd(init, std::make_index_sequence<s> {});
    }

    template <std::size_t... I>
    static constexpr std::array<inner_type, s> impl_to_arraynd(const native_type& init, std::index_sequence<I...>)
    {
        return { inner_type(init[I])... };
    }

    constexpr arraynd()
    {
    }

    constexpr arraynd(const native_type& init)
        : inner(to_arraynd(init))
    {

    }

    std::array<inner_type, s>   inner;
};

template <class T, size_t s>
struct arraynd<T, s>
{
    typedef T inner_type;
    typedef T native_type[s];

    static constexpr std::array<inner_type, s> to_arraynd(const native_type& init)
    {
        return impl_to_arraynd(init, std::make_index_sequence<s> {});
    }

    template <std::size_t... I>
    static constexpr std::array<inner_type, s> impl_to_arraynd(const native_type& init, std::index_sequence<I...>)
    {
        return { inner_type(init[I])... };
    }

    constexpr arraynd()
    {
    }

    constexpr arraynd(const native_type& init)
        : inner(to_arraynd(init))
    {

    }

    std::array<inner_type, s>   inner;
};

int main()
{
    constexpr int a2native[2][3] = { { 1, 2, 3 }, { 1, 2, 3 } };
    constexpr std::array<std::array<int, 3>, 2>   a2std = { { { 1, 2, 3 }, { 1, 2, 3 } } };
    constexpr arraynd<int, 2, 3> a2({ { 1, 2, 3 }, { 1, 2, 3 } });

    return 0;
}