[Boost-users] [multiarray] problems passing views by reference

100 views
Skip to first unread message

Rhys Ulerich

unread,
Jan 5, 2010, 11:23:30 PM1/5/10
to boost...@lists.boost.org
Recently, Hanan Sadar asked about a multi_array fill implementation
[1]. The standard std::fill_n(x.data(),x.num_elements(),v) answer
only works when x is a boost::multi_array or boost::multi_array_ref
but does not handle the general MultiArray concept.

I decided to implement an arbitrary dimensional MultiArray fill
capable of handling such views correctly. It's been absolutely
miserable for reasons I don't understand but which resemble comments
from James Amundson's recent thread [2]. Attached is my attempt with
two exasperating lines marked by "Cannot use reference, why?".

For a non-multi_array, non-multi_array_ref instance (i.e. a view)
using a signature like
template< class Array, class V > void operator()(Array x, const V &v);
allows the code to compile and operate correctly. However, it incurs
pass-by-value overhead. Using
a signature like
template< class Array, class V > void operator()(Array &x, const V &v);
using pass-by-reference dies at compilation time. All of my attempts
to use MultiArray's associated typedefs die, including hours of
mucking with MultiArray::reference.

What am I missing here? Why can't I pass a general MultiArray view
type by reference?

- Rhys

[1] http://groups.google.com/group/boost-list/browse_thread/thread/829ebea7fef28db0/57485403b4e809dc
[2] http://groups.google.com/group/boost-list/browse_thread/thread/4531a7c35a5865fc/6fdec1189d01acde

test_fill.cc

Ronald Garcia

unread,
Jan 11, 2010, 4:11:30 PM1/11/10
to boost...@lists.boost.org
Hi Rhys,

The problem might be the body of fill_functor for the general case.
"*i" will produce a temporary (a subarray), which you are then trying
to pass immediately by reference to the smaller fill_functor case. C+
+ doesn't let you pass temporaries by reference, which is a real
problem when you need proxy references like MultiArray does. The
solution should be as follows:

for (typename Array::iterator i = x.begin(); i != x.end(); +
+i) {
typename Array::iterator::reference ri = *i;
f(ri,v);
}


That is, assign the temporary to a variable before you call f.

Cheers,
Ron

> <test_fill.cc>_______________________________________________
> Boost-users mailing list
> Boost...@lists.boost.org
> http://lists.boost.org/mailman/listinfo.cgi/boost-users

_______________________________________________
Boost-users mailing list
Boost...@lists.boost.org
http://lists.boost.org/mailman/listinfo.cgi/boost-users

Rhys Ulerich

unread,
Jan 13, 2010, 11:48:23 AM1/13/10
to boost...@lists.boost.org
> The problem might be the body of fill_functor for the general case.  "*i"
> will produce a temporary (a subarray), which you are then trying to pass
> immediately by reference to the smaller fill_functor case.  C++ doesn't let

> you pass temporaries by reference, which is a real problem when you need
> proxy references like MultiArray does.  The solution should be as follows:
>
>        for (typename Array::iterator i = x.begin(); i != x.end(); ++i) {
>          typename Array::iterator::reference ri = *i;
>            f(ri,v);
>        }

Ron's suggestion did fix my problem. Thanks Ron.

Just in case anyone's ever searching for a general MultiArray fill
implementation, I've attached the now working code/test case.

This might not be a bad example to add to the MultiArray tutorial, both
because it touches on an easy mistake and because people ask about
fill with some frequency.

- Rhys

test_fill.cc

Ronald Garcia

unread,
Jan 14, 2010, 4:06:07 PM1/14/10
to boost...@lists.boost.org
Thanks for the contribution Rhys. I think it will make a fine
addition to MultiArray.

Best,
Ron

Reply all
Reply to author
Forward
0 new messages