遍历 boost::multi_array 视图
Iterate through a boost::multi_array view
我想了解如何使用 boost::multi_array 提供的视图功能。具体来说,我希望能够在单个循环内迭代表示初始矩阵(不一定是连续的)特定子矩阵的视图的所有元素。似乎提供的迭代器不会做我想要的(或任何东西,它不会编译)。
在下面的例子中,我有一个 2x6 矩阵,我想得到它的 2x4 子矩阵,所以,如果我尝试打印它,我希望得到 "BoosLion"。事实上,如果我对每个维度进行迭代,情况就是如此。但是当我尝试使用单个迭代器进行迭代时,程序将无法编译。
#include <boost/multi_array.hpp>
#include <iostream>
int main()
{
boost::multi_array<char, 2> a{boost::extents[2][6]};
a[0][0] = 'B';
a[0][1] = 'o';
a[0][2] = 'o';
a[0][3] = 's';
a[0][4] = 't';
a[0][5] = '[=11=]';
a[1][0] = 'L';
a[1][1] = 'i';
a[1][2] = 'o';
a[1][3] = 'n';
a[1][4] = 's';
a[1][5] = '[=11=]';
typedef boost::multi_array<char, 2>::array_view<2>::type array_view;
typedef boost::multi_array_types::index_range range;
array_view b = a[boost::indices[range{0,2}][range{0,4}] ];
for (unsigned int i = 0; i < 2; i++ ) {
for (unsigned int j = 0; j < 4; j++ ) {
std::cout << b[i][j] << std::endl;
}
}
// I want to do something like this:
// for (auto itr = b.begin(); itr < b.end(); ++itr) {
// std::cout << *itr << std::endl;
// }
}
有谁知道如何只用一个循环进行迭代?我尝试搜索文档,但找不到任何相关内容。另外,如果有人知道另一个图书馆可以做到这一点,请告诉我,谢谢!
这是一种方法:
#include <iostream>
#include <boost/multi_array.hpp>
// Functor to iterate over a Boost MultiArray concept instance.
template<typename T, typename F, size_t Dimensions = T::dimensionality>
struct IterateHelper {
void operator()(T& array, const F& f) const {
for (auto element : array)
IterateHelper<decltype(element), F>()(element, f);
}
};
// Functor specialization for the final dimension.
template<typename T, typename F>
struct IterateHelper<T, F, 1> {
void operator()(T& array, const F& f) const {
for (auto& element : array)
f(element);
}
};
// Utility function to apply a function to each element of a Boost
// MultiArray concept instance (which includes views).
template<typename T, typename F>
static void iterate(T& array, const F& f) {
IterateHelper<T, F>()(array, f);
}
int main() {
boost::multi_array<char, 2> a{boost::extents[2][6]};
a[0][0] = 'B';
a[0][1] = 'o';
a[0][2] = 'o';
a[0][3] = 's';
a[0][4] = 't';
a[0][5] = '[=10=]';
a[1][0] = 'L';
a[1][1] = 'i';
a[1][2] = 'o';
a[1][3] = 'n';
a[1][4] = 's';
a[1][5] = '[=10=]';
typedef boost::multi_array<char, 2>::array_view<2>::type array_view;
typedef boost::multi_array_types::index_range range;
array_view b = a[boost::indices[range{0,2}][range{0,4}] ];
// Use the utility to apply a function to each element.
iterate(b, [](char& c) {
std::cout << c << std::endl;
});
return 0;
};
上面的代码定义了一个效用函数 iterate()
,您向其传递一个满足 Boost MultiArray 概念(包括视图)的对象和一个应用于每个元素的函数。效用函数通过使用一个 Functor 来递归迭代每个维度。
update2
根据@rhashimoto 提供的答案,我试着做了一些概括。具有以下功能
// moving the judgement of dimensionality to the function's return-type
template<class T, class F>
typename std::enable_if<(T::dimensionality==1), void>::type IterateArrayView(T& array, F f) {
for (auto& element : array) {
f(element);
}
}
template<class T, class F>
typename std::enable_if<(T::dimensionality>1), void>::type IterateArrayView(T& array, F f) {
for (auto element : array) {
IterateArrayView<decltype(element), F>(element, f);
}
}
// given f() takes extra arguments
template<class T, class F, class... Args>
typename std::enable_if<(T::dimensionality==1), void>::type IterateArrayView(T& array, F f, Args& ...args) {
for (auto& element : array) {
f(element, args...);
}
}
template<class T, class F, class... Args>
typename std::enable_if<(T::dimensionality>1), void>::type IterateArrayView(T& array, F f, Args& ...args) {
for (auto element : array) {
IterateArrayView<decltype(element), F, Args...>(element, f, args...);
}
}
您可以将一个函数应用于带有额外参数的每个元素。例如
int main() {
using array_type = boost::multi_array<int, 3>;
using view_type = array_type::array_view<3>::type;
using range = boost::multi_array_types::index_range;
array_type data;
data.resize(boost::extents[16][4][4]);
view_type view = data[boost::indices[range(0,4)][range()][range()]];
int count = 0;
IterateArrayView(view, [](int &i, int &count) { i = count++;}, count);
std::cout << view[3][3][3] << std::endl; // output 63 (=4^3-1)
return 0;
}
下面是错误的旧解决方案
事实上,boost::multi_array_view
提供了一个名为 origin()
的方法(参考:here):
template <typename T, std::size_t NumDims>
class multi_array_view :
public const_multi_array_view<T,NumDims,T*>
{
// a lot of code ...
element* origin() { return this->base_+this->origin_offset_; }
// a lot of code ...
};
所以你可以通过
遍历它
array_view b;
for (auto it = b.origin(); it != b.origin()+b.num_elements(); it++) {
// do something, e.g.
*it = 'a';
}
对于boost::multi_array
,您可以使用auto it = b.data()
代替。
update1:抱歉,我的解决方案不正确。我刚刚发现,尽管 b.origin()
为您提供了正确的迭代器,但您仍在循环 multi_array 而不是 array_view。
我想了解如何使用 boost::multi_array 提供的视图功能。具体来说,我希望能够在单个循环内迭代表示初始矩阵(不一定是连续的)特定子矩阵的视图的所有元素。似乎提供的迭代器不会做我想要的(或任何东西,它不会编译)。
在下面的例子中,我有一个 2x6 矩阵,我想得到它的 2x4 子矩阵,所以,如果我尝试打印它,我希望得到 "BoosLion"。事实上,如果我对每个维度进行迭代,情况就是如此。但是当我尝试使用单个迭代器进行迭代时,程序将无法编译。
#include <boost/multi_array.hpp>
#include <iostream>
int main()
{
boost::multi_array<char, 2> a{boost::extents[2][6]};
a[0][0] = 'B';
a[0][1] = 'o';
a[0][2] = 'o';
a[0][3] = 's';
a[0][4] = 't';
a[0][5] = '[=11=]';
a[1][0] = 'L';
a[1][1] = 'i';
a[1][2] = 'o';
a[1][3] = 'n';
a[1][4] = 's';
a[1][5] = '[=11=]';
typedef boost::multi_array<char, 2>::array_view<2>::type array_view;
typedef boost::multi_array_types::index_range range;
array_view b = a[boost::indices[range{0,2}][range{0,4}] ];
for (unsigned int i = 0; i < 2; i++ ) {
for (unsigned int j = 0; j < 4; j++ ) {
std::cout << b[i][j] << std::endl;
}
}
// I want to do something like this:
// for (auto itr = b.begin(); itr < b.end(); ++itr) {
// std::cout << *itr << std::endl;
// }
}
有谁知道如何只用一个循环进行迭代?我尝试搜索文档,但找不到任何相关内容。另外,如果有人知道另一个图书馆可以做到这一点,请告诉我,谢谢!
这是一种方法:
#include <iostream>
#include <boost/multi_array.hpp>
// Functor to iterate over a Boost MultiArray concept instance.
template<typename T, typename F, size_t Dimensions = T::dimensionality>
struct IterateHelper {
void operator()(T& array, const F& f) const {
for (auto element : array)
IterateHelper<decltype(element), F>()(element, f);
}
};
// Functor specialization for the final dimension.
template<typename T, typename F>
struct IterateHelper<T, F, 1> {
void operator()(T& array, const F& f) const {
for (auto& element : array)
f(element);
}
};
// Utility function to apply a function to each element of a Boost
// MultiArray concept instance (which includes views).
template<typename T, typename F>
static void iterate(T& array, const F& f) {
IterateHelper<T, F>()(array, f);
}
int main() {
boost::multi_array<char, 2> a{boost::extents[2][6]};
a[0][0] = 'B';
a[0][1] = 'o';
a[0][2] = 'o';
a[0][3] = 's';
a[0][4] = 't';
a[0][5] = '[=10=]';
a[1][0] = 'L';
a[1][1] = 'i';
a[1][2] = 'o';
a[1][3] = 'n';
a[1][4] = 's';
a[1][5] = '[=10=]';
typedef boost::multi_array<char, 2>::array_view<2>::type array_view;
typedef boost::multi_array_types::index_range range;
array_view b = a[boost::indices[range{0,2}][range{0,4}] ];
// Use the utility to apply a function to each element.
iterate(b, [](char& c) {
std::cout << c << std::endl;
});
return 0;
};
上面的代码定义了一个效用函数 iterate()
,您向其传递一个满足 Boost MultiArray 概念(包括视图)的对象和一个应用于每个元素的函数。效用函数通过使用一个 Functor 来递归迭代每个维度。
update2
根据@rhashimoto 提供的答案,我试着做了一些概括。具有以下功能
// moving the judgement of dimensionality to the function's return-type
template<class T, class F>
typename std::enable_if<(T::dimensionality==1), void>::type IterateArrayView(T& array, F f) {
for (auto& element : array) {
f(element);
}
}
template<class T, class F>
typename std::enable_if<(T::dimensionality>1), void>::type IterateArrayView(T& array, F f) {
for (auto element : array) {
IterateArrayView<decltype(element), F>(element, f);
}
}
// given f() takes extra arguments
template<class T, class F, class... Args>
typename std::enable_if<(T::dimensionality==1), void>::type IterateArrayView(T& array, F f, Args& ...args) {
for (auto& element : array) {
f(element, args...);
}
}
template<class T, class F, class... Args>
typename std::enable_if<(T::dimensionality>1), void>::type IterateArrayView(T& array, F f, Args& ...args) {
for (auto element : array) {
IterateArrayView<decltype(element), F, Args...>(element, f, args...);
}
}
您可以将一个函数应用于带有额外参数的每个元素。例如
int main() {
using array_type = boost::multi_array<int, 3>;
using view_type = array_type::array_view<3>::type;
using range = boost::multi_array_types::index_range;
array_type data;
data.resize(boost::extents[16][4][4]);
view_type view = data[boost::indices[range(0,4)][range()][range()]];
int count = 0;
IterateArrayView(view, [](int &i, int &count) { i = count++;}, count);
std::cout << view[3][3][3] << std::endl; // output 63 (=4^3-1)
return 0;
}
下面是错误的旧解决方案
事实上,boost::multi_array_view
提供了一个名为 origin()
的方法(参考:here):
template <typename T, std::size_t NumDims>
class multi_array_view :
public const_multi_array_view<T,NumDims,T*>
{
// a lot of code ...
element* origin() { return this->base_+this->origin_offset_; }
// a lot of code ...
};
所以你可以通过
遍历它array_view b;
for (auto it = b.origin(); it != b.origin()+b.num_elements(); it++) {
// do something, e.g.
*it = 'a';
}
对于boost::multi_array
,您可以使用auto it = b.data()
代替。
update1:抱歉,我的解决方案不正确。我刚刚发现,尽管 b.origin()
为您提供了正确的迭代器,但您仍在循环 multi_array 而不是 array_view。