1

Related questions have been asked here before, but I still haven't found a satisfactory answer, so I will try to explain my problem and hope someone can enlighten me.

I am currently writing some code using boost::multi_array, and the code itself is also dimension independent. I need to loop over all elements stored in the multi_array and do something with them. I am looking to do this in a STL-like way:

for_each(begin(array), end(array), function);

Or something similar. Other questions have pointed me to an example on the boost page itself:

for_each example
for_each implementation

Which is more or less exactly what I want. The problem comes when one tries to simply import this code into a larger program. One would naturally like to both wrap the function itself in some namespace, and use for example the C++ functionals as the function object. Doing any of these two will create template lookup problems for the compiler.

Does anyone know either how I can work around the template lookup issue, or an alternative way of doing it (that is hopefully as pretty)?

Additional info:

Compilation error when wrapping the for_each definitions in a namespace

./for_each.hpp:28:3: error: call to function 'for_each' that is neither visible in the template definition nor found by
argument-dependent lookup
  for_each(type_dispatch,A.begin(),A.end(),xform);
  ^
./for_each.hpp:41:5: note: in instantiation of function template specialization
'boost_utilites::for_each<boost::detail::multi_array::sub_array<double, 1>,
      double, times_five>' requested here
    for_each(type_dispatch,*begin,xform);
    ^
./for_each.hpp:50:3: note: in instantiation of function template specialization 'boost_utilites::for_each<double,
      boost::detail::multi_array::array_iterator<double, double *, mpl_::size_t<2>, boost::detail::multi_array::sub_array<double,
1>,
      boost::random_access_traversal_tag>, times_five>' requested here
  for_each(boost::type<typename Array::element>(),A.begin(),A.end(),xform);
  ^
foreach_test.cpp:46:19: note: in instantiation of function template specialization
'boost_utilites::for_each<boost::multi_array<double, 2,
      std::allocator<double> >, times_five>' requested here
  boost_utilites::for_each(A,times_five());
                  ^
./for_each.hpp:37:6: note: 'for_each' should be declared prior to the call site or in an associated namespace of one of its
arguments
void for_each (const boost::type<Element>& type_dispatch,
     ^
1 error generated.

When using a std::function object instead of the times_five object in the example, one gets basically the same compilation error.

Compiled with clang version 3.4-1ubuntu3.

1 Answers1

2

Just

std::for_each(array.data(), array.data() + array.num_elements(), function);

To make it work with functions that expect an random-access range (with .begin(), .end() and .size()) use

auto elements = boost::make_iterator_range(array.data(), array.data() + array.num_elements();

// e.g.
for (auto& element : elements) {

    ...
}

I personally like to use this with generate_n or fill_n etc.:

std::for_each(array.data(), array.num_elements(), 0);

Reference docs

  • element* data();
  • const element* data() const;

    This returns a pointer to the beginning of the contiguous block that contains the array's data. If all dimensions of the array are 0-indexed and stored in ascending order, this is equivalent to origin(). Note that const_multi_array_ref only provides the const version of this function.

and

  • size_type a.num_elements()

    This returns the number of elements contained in the array. It is equivalent to the following code:

    std::accumulate(a.shape(),a.shape+a.num_dimensions(), 
               size_type(1),std::multiplies<size_type>());> 
    
sehe
  • 374,641
  • 47
  • 450
  • 633
  • Thanks, that does indeed seem to do what I want. Specially thanks for the tip on the make_iterator_range, that did make things a bit prettier. I have always preferred not to directly access the underlying containers of these data structures, such as calling std::vector::data. But with the iterator_range you can at least wrap the data access away and hide it. – Aleksandra Glesaaen Mar 26 '15 at 16:24