I want to understand how to use the view functionality provided by boost::multi_array. Specifically, I want to be able to iterate within a single loop over all elements of a view that represents a particular submatrix of the initial matrix (not necessarily continuous). It seems that the iterator provided will not do what I want (or anything, it will not compile).
In the following example, I have a 2x6 matrix and I want to get its 2x4 submatrix so, if I try to print it I would expect to get "BoosLion". Indeed this is the case if I iterate for each dimension. But when I try to do the iteration with a single iterator, the program will not compile.
#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] = '\0';
a[1][0] = 'L';
a[1][1] = 'i';
a[1][2] = 'o';
a[1][3] = 'n';
a[1][4] = 's';
a[1][5] = '\0';
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;
// }
}
Does anyone know how to iterate with only a single loop? I tried searching the documentation but have been unable to find anything relevant. Also, if anyone knows of another library that can do this, let me know, thank you!
Here is one way to do this:
#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] = '\0';
a[1][0] = 'L';
a[1][1] = 'i';
a[1][2] = 'o';
a[1][3] = 'n';
a[1][4] = 's';
a[1][5] = '\0';
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;
};
The code above defines a utility function iterate()
, to which you pass an object satisfying the Boost MultiArray concept (which includes views) and a function to apply to each element. The utility function works by using a Functor that iterates over each dimension recursively.