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 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