【问题标题】:multi-dimensional array initialization based on std::array基于std::array的多维数组初始化
【发布时间】:2018-09-13 07:57:05
【问题描述】:

看到 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
}

【问题讨论】:

  • 如果您担心嵌套数组的类型看起来很难看,请考虑使用 typedef 或 using 声明。
  • 访问数组为:a2b.arr = {...} 完成了这项工作,但我不知道如何通过聚合初始化来做到这一点
  • 我建议您查看一个库,例如 eigen 或 amadrillo。你不必重新发明它。 eigen.tuxfamily.org/dox-devel/unsupported/…

标签: c++


【解决方案1】:

如果你使用成员类的方式,你必须用 {} 再包装一次数组内容(你也不用std::array&lt;int, 2&gt; 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?

【讨论】:

  • std::array 的大小参数是 std::size_t 而不是 int,请考虑改用它
  • 谢谢,所以在我原来的问题的形式中,答案是更多的大括号:arraynd_b a3b = { { { { { { 0, 1 } } }, { { { 1, 0 } } }, { { { 2, 4 } } } } } };
  • 所以,arr_mult_dim_t arr_3 的类型实际上是 std::array<:array>, 2 >, 2>, 2>,它只是使用嵌套的 using 声明定义的。这在大括号方面看起来确实更好。
  • @RadAd 是的,完全正确
【解决方案2】:

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-05
    • 1970-01-01
    • 2011-03-19
    • 1970-01-01
    • 2012-02-10
    • 2015-07-25
    相关资源
    最近更新 更多