【问题标题】:One-line initialiser for Boost.MultiArrayBoost.MultiArray 的单行初始化程序
【发布时间】:2012-01-11 17:58:55
【问题描述】:

我有一个 n 维 Boost.MultiArray 我初始化如下:

const int n=3, size=4; //# of dimensions and size of one dimension
boost::multi_array<char,n> arr;
boost::array<size_t,n> extents; //size of each dimension
extents.assign(size); //assign size to each dimension -> {{4, 4, 4}}
arr.resize(extents);

所以我有 4 行代码来获取 MultiArray,但我想在一行中完成。 有没有什么简单的方法可以生成一个 n 维的 MultiArray,每个维度的长度为 size(所以我可以写 arr(samevaluearray(n,size))),还是我错过了一个方便的 MultiArray 构造函数?

编辑:它应该可以在不依赖于特定 n 值的情况下工作,即 arr({{size,size}} 仅适用于 n=2

由于可能不清楚:boost::multi_array&lt;char,n&gt;(boost::extents[4][4][4]) 正确初始化了一个 4x4x4 数组,但是每次在源代码中更改 n 时,每次初始化都必须手动更新,所以它不是一个选项。

【问题讨论】:

  • 天啊,把它包装在一个接受两个整数并返回boost::multi_array的函数中是不是很难?
  • 或者为了真正的乐趣,将其包装在宏中;-)

标签: c++ boost boost-multi-array


【解决方案1】:

您可以将数组的创建封装到一个辅助函数中:

template <typename T, size_t N>
boost::multi_array<T, N> make_regular_matrix(const size_t m)
{
    boost::multi_array<T, N> arr;
    boost::array<size_t, N> extents;
    extents.assign(m);
    arr.resize(extents);

    return arr;
}

const int n = 3;
int size = 4; // Can be const as well, but this is not mandatory

auto arr = make_regular_matrix<char, n>(size);

如果不能使用auto,则必须复制模板参数:

boost::multi_array<char, n> arr = make_regular_matrix<char, n>(size);

make_regular_matrix 函数可以缩短为使用std::vector,就像您在回答中所做的那样;我不知道这个实现是否会更好。辅助函数的目的是隐藏数组的创建,但也可以编写其他版本,例如用给定值初始化数组元素:

template <size_t N, typename T> //switched order for deduction
boost::multi_array<T, N> make_regular_matrix(const size_t m, const T & value)
{
     boost::multi_array<T, N> arr(std::vector<size_t>(n, m));

     std::fill(arr.data(), arr.data() + arr.num_elements(), value);

     return arr;
}

auto arr = make_regular_matrix<4>(3, 'z'); //creates a 3x3x3x3 matrix
                                           //filled with 'z's

【讨论】:

    【解决方案2】:

    原来,std::vector 有一个构造函数,它构造一个具有重复 n 次的常数值的向量,因此可能的解决方案如下所示:

    const int n=2, size=4; //# of dimensions and size of one dimension
    boost::multi_array<char,n> arr(std::vector<size_t>(n,size));
    

    这会初始化一个 n 维 multi_array,每个维度的大小都设置为 size。

    【讨论】:

    • 对,您没有解决问题 + 忘记指定您正在创建的数组类型。更不用说创建向量的巨大开销了:-D
    • @VladLazarenko 忘记将
    • 嗯,它会在某种程度上起作用。但我担心你以后会遇到问题,不得不到处更改代码。这是因为我有一种感觉,你并没有真正理解const int n 在这个地方的作用——它不是一个变量,而是一个常量编译时表达式。现在,尝试编写一个将两个数组相乘的函数,接受Nsize 和两个数组作为其参数。你的代码很快就会失败,因为n 在编译时不会被编译器知道。
    • 乘以 2 个数组是微不足道的,因为我只使用两个数组的 1D 视图,但是由于您不相信我知道我在做什么,这里有一个函数来迭代n维数组:template&lt;int level=0&gt; void iterate(boost::multi_array&lt;char,n&gt;&amp; arr, boost::array&lt;size_t,n&gt; index){for(int i=0;i&lt;size;++i) {index[level]=i; iterate&lt;level+1&gt;(arr,index);}} template&lt;&gt; void iterate&lt;n&gt;(boost::multi_array&lt;char,n&gt;&amp; arr, boost::array&lt;size_t,n&gt; index){ arr(index)++;}
    • 这是一个糟糕的功能。编译器生成的代码量会将其大小变成三个维度...您还忘记将nlevel 一起指定为模板参数...但是,无论如何...
    【解决方案3】:

    Boost Multi-Array documentation,可以,一行初始化即可:

    typedef boost::multi_array<double, 3> array_type;
    typedef array_type::index index;
    array_type A(boost::extents[3][4][2]);
    

    typedefs 是为了便于阅读,你可以很容易地为你的例子做:

    boost::multi_array<int, 2> arr(boost::extents[2][4]);
    

    【讨论】:

    • 这有效,但仅适用于 n=2。每隔一个n,需要手动调整代码。
    • @tstenner:呃……你还期待什么?您必须至少调整 一些 代码。你想做什么来创建一个新的multi_array
    • 实际上,您已经想出了 OP 正在寻找的东西,所以 +1。出于某种原因,他仍然没有得到它并回答了他自己的问题,说了完全相同的话......伤心。
    • 其实它生成一个3x4x2-array,第二个版本生成一个2x4-array。如果我每次想更改维数时都想编辑代码,我自己会这样做。
    猜你喜欢
    • 2013-11-18
    • 2019-04-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-16
    • 1970-01-01
    相关资源
    最近更新 更多