$include_dir="/home/hyper-archives/boost-users/include"; include("$include_dir/msg-header.inc") ?>
From: Beth Jacobson (bethj_at_[hidden])
Date: 2006-05-16 14:34:14
On a recent thread, Bruno Martinez provided a std::for_each-like
function for multi_arrays which lets users apply a function to each 
element in a multi_array or view without having to know anything about 
the dimensions. I've been playing around with it (on MSVC 7.1) and it 
works perfectly. It seems like a good utility for anyone using 
boost.multi_array.
Working from Bruno's code, I wrote a similar std::accumulate-like 
function, which could also be generally useful. I'm fairly new to 
template programming, so if someone could look over the code below and 
see if I've done something dangerous or stupid, it would be much 
appreciated.
Also, is there some standard Boost way of making this sort of code 
generally available?  It probably isn't at a level where it could be 
included in the library, but it seems like a shame to just let it 
languish in the bowels of the mailing list archive.
Anyway, here are both algorithms:
My accumulate-like function:
template<class MA, class T, class F, int dim>
struct accum_impl
{
        F f;
        T &val;
        accum_impl(T &val, F f) : f(f), val(val) {}
        T operator()(MA& ma)
        {
                std::for_each(ma.begin(), ma.end(), accum_impl<typename
                        boost::add_const<MA::const_reference>::type, T, F, dim-1>(val, f));
                return val;
        }
};
template<class Ref, class T, class F>
struct accum_impl<Ref, T, F, 0>
{
        F f;
        T &val;
        accum_impl(T &val, F &f) : f(f), val(val) {}
        T operator()(Ref r)
        {
                val = f(val, r);
                return val;
        }
};
template<class MA, class T, class F>
T multi_accum(MA& ma, T init, F f)
{
        accum_impl<MA, T, F, MA::dimensionality> impl(init, f);
        return impl(ma);
}
And a test:
typedef boost::multi_array<int, 3> array_type;
typedef array_type::index_range range;
typedef array_type::index index;
array_type B(boost::extents[4][2][3]);
int values = 0;
for(index i = 0; i != 4; ++i)
        for(index j = 0; j != 2; ++j)
                for(index k = 0; k != 3; ++k)
                        B[i][j][k] = values++;
array_type::array_view<2>::type myview =
        B[ boost::indices[range(1,3)][1][range(0,2)] ];
cout << "Sum: " << multi_accum(myview, 0, std::plus<int>()) << endl;
cout << "Product: " << multi_accum(myview, 1, std::multiplies<int>()) << 
endl;
Bruno Martinez's for_each-like function:
template<class MA, class F, int dim>
struct for_each_impl
{
        F f;
        for_each_impl(F f) : f(f) {}
        void operator()(MA& ma)
        {
                std::for_each(ma.begin(), ma.end(), for_each_impl<typename
MA::reference, F, dim-1>(f));
        }
};
template<class Ref, class F>
struct for_each_impl<Ref, F, 0>
{
        F f;
        for_each_impl(F f) : f(f) {}
        void operator()(Ref r)
        {
                f(r);
        }
};
template<class MA, class F>
void multi_for_each(MA& ma, F f)
{
        for_each_impl<MA, F, MA::dimensionality> impl(f);
        impl(ma);
}
And a test:
        typedef boost::multi_array<double, 3> array_type;
        typedef array_type::index index;
        array_type myarray(boost::extents[3][4][2]);
        typedef array_type::index_range range;
        array_type::array_view<3>::type myview =
                myarray[ boost::indices[range(0,2)][range(1,3)][range(0,4,2)] ];
        multi_for_each(myview, _1 = 56);