
Hi Patrick, On Thu, Jan 27, 2011 at 1:53 AM, Patrick Horgan <phorgan1@yahoo.com> wrote:
On Sat, Jan 22, 2011 at 4:21 PM, Nathan Crookston
I occasionally want to use something akin to MPL's zip_view and unpack_args with my ranges More details?
Fair enough -- I'll try to give some brief motivation and examples: I often find that I have ranges whose elements are related to each other. For example, I may have a list of images and a list of offsets: //Assume 0th elements of images and offsets are related, and so forth. vector<Image> images(...); vector<Offset> offsets(...); If I wish to create a mosaic by adding each image/offset pair to an aggregate image I currently have a few options: //First option -- iterators for both. Requires an awful lot of typing, introduces // a new variable outside the for-loop scope. Code using an index is much more concise, // but both suffer from the problem of not being composable (more on that later). Mosaic mosaic; vector<Offset>::iterator j = offsets.begin() for(vector<Image>::iterator i = images.begin(); i != images.end() && j != offsets.end(); ++i, ++j) mosaic.add(*i, *j); //Second option -- create a zip_iterator [1]. This obviously requires a lot more typing. // I think this is moving in the right direction. for_each(boost::make_zip_iterator(boost::make_tuple(images.begin(), offsets.begin())), boost::make_zip_iterator(boost::make_tuple(images.end(), offsets.end())), AddToMosaic(mosaic)); I decided to create a new range adaptor based the zip_iterator which reduces the verbosity of the loop declaration. Such an adaptor is common for this problem [2][3]. I was surprised that I couldn't find this already in the range library. (Feel free to disabuse me if necessary.) //Using the zip range adaptor. Creates begin and end zip_iterators under the hood. boost::for_each(zip(images, offsets), AddToMosaic(mosaic)); The previous looks much nicer and more expressive to my eye. Note that we're not copying any elements -- it's a lazy adaptor, like the other range adaptors. It's also composable: //Passes elements 0,2,4, etc. packed into a tuple of references. boost::for_each(zip(images, offsets) | strided(2), AddToMosaic(mosaic)); My implementation of zip supports multiple arguments (controlled by a preprocessor symbol, currently 5). Hopefully my reasons for suggesting zip are clear. I also wrote a function corresponding to mpl::unpack_args. If we examine the declaration of AddToMosaic it's clear that using zip() is still burdening us with syntax contortions: struct AddToMosaic { AddToMosaic(Mosaic& rMosaic) : m_rMosaic(rMosaic) {} void operator()(const boost::tuple<Image&, Offset&>& tuple) { m_rMosaic.add(boost::get<0>(tuple), boost::get<1>(tuple)); } }; It would be nice to have separate arguments rather than having to write an adaptor functor for each use of zip(): boost::for_each(zip(images, offsets) | strided(2), unzip(AddToMosaic(mosaic))); struct AddToMosaic { AddToMosaic(Mosaic& rMosaic) : m_rMosaic(rMosaic) {} void operator()(const Image& image, const Offset& offset) { m_rMosaic.add(image, offset); } }; The unpack() function would be useful for the zip_iterator as well. For more examples of zip and unpack usage see my original post [4]. This has been very useful in my work, and I think it can be generally useful. Thanks, Nate [1] <http://www.boost.org/doc/libs/1_44_0/libs/iterator/doc/zip_iterator.html> [2] <http://www.digitalmars.com/d/2.0/phobos/std_range.html#zip> [3] <http://www.boost.org/doc/libs/1_44_0/libs/mpl/doc/refmanual/zip-view.html> [4] <http://permalink.gmane.org/gmane.comp.lib.boost.user/65266>