returning range adaptor generator

What should be the return type for a function that returns an adapted range? E.g. template<class Range> xxx getIndirected( const Range& r ) { return r | boost::adaptors::indirected; } The use case being, providing a API with these little useful helpers without forcing the user to know about Boost.Range at all. Like so: #include <myapi.hpp> #include <boost/foreach.hpp> LegacyPointerContainers f; // contains Foo pointers BOOST_FOREACH( Foo& f, TraverseFoo( f ) ) { } /// where in myapi.hpp xxx TraverseFoo( LegacyPointerContainers& f ) { return getIndirected( makeRange(f) ) ; } PS: This is all C++03. No autos. Thanks Nick

On Tue, Oct 1, 2013 at 4:21 PM, Nick Stokes <randomaccessiterator@gmail.com> wrote:
What should be the return type for a function that returns an adapted range? E.g.
template<class Range> xxx getIndirected( const Range& r ) { return r | boost::adaptors::indirected; }
boost::indirected_range<Range> -kyle

On Tue, Oct 1, 2013 at 4:55 PM, Kyle Lutz <kyle.r.lutz@gmail.com> wrote:
On Tue, Oct 1, 2013 at 4:21 PM, Nick Stokes [..] boost::indirected_range<Range>
Thanks. But the question is not really about one single adaptor that indirected is. That was just an example (although your answer was useful, thank you) How about in general? Say, template<class Range> xxx getPuffedRange( Range& r ) { return r | indirected | filtered(puff) | etc; }

Thanks. But the question is not really about one single adaptor that indirected is. That was just an example (although your answer was useful, thank you)
How about in general? Say,
template<class Range> xxx getPuffedRange( Range& r ) { return r | indirected | filtered(puff) | etc; }
Your options are: 1) Use the exact type of the adapted range: template <class Range> filtered_range<PuffT, indirected_range<Range>> getPuffedRange(Range& r) { return r | indirected | filtered(puff); } In C++11 you can make this nicer by using decltype() and late-specified return types: template <class Range> auto getPuffedRange(Range& r) -> decltype(r | indirected | filtered(puff)) { return r | indirected | filtered(puff); } In C++14 you can make this even nicer by using return type deduction: template <class Range> auto getPuffedRange(Range& r) { return r | indirected | filtered(puff); } 2) Use type erasure to erase everything about the range besides its value type: template <class Range> TypeErasedRange<E> getPuffedRange(Range& r) { return r | indirected | filtered(puff); } (where E is the element type of the returned range, which in this case would be range_value<Range>::type, but could be something else if you have different adaptors). You can do this using Boost.Range's any_range [1], or roll your own type erasure using Boost.TypeErasure [2] (or manually). 3) Eagerly populate a container like vector and return that: template <class Range> vector<E> getPuffedRange(Range& r) { vector<E> result; push_back(result, r | indirected | filtered(puff)); return result; } (where again E is the element type of the returned range). Obviously there are tradeoffs between these three approaches: (1) incurs no runtime penalty but it's clumsy to write. (2) incurs a virtual function call to every iterator operation on the type-erased range (3) loses the laziness that range adaptors give you Regards, Nate [1] http://www.boost.org/doc/libs/1_54_0/libs/range/doc/html/range/reference/ran... [2] http://www.boost.org/doc/libs/1_54_0/doc/html/boost_typeerasure.html
participants (3)
-
Kyle Lutz
-
Nathan Ridge
-
Nick Stokes