What are the benefits of using boost::any_range
?
Here is an example:
typedef boost::any_range<
int
, boost::forward_traversal_tag
, int
, std::ptrdiff_t
> integer_range;
void display_integers(const integer_range& rng)
{
boost::copy(rng,
std::ostream_iterator<int>(std::cout, ","));
std::cout << std::endl;
}
int main(){
std::vector<int> input{ ... };
std::list<int> input2{ ... };
display_integers(input);
display_integers(input2);
}
But the same functionality with more efficiency can be achieved with a template parameter, which satisfies the ForwardRange concept:
template <class ForwardRange>
void display_integers(const ForwardRange& rng)
{
boost::copy(rng,
std::ostream_iterator<int>(std::cout, ","));
std::cout << std::endl;
}
So I am searching for scenarios when it is worth to use any_range. Maybe I am missing something.
This technique is called Type Erasure. There is a full article describing the pros and cons on the example of any_iterator
: On the Tension Between Object-Oriented and Generic Programming in C++.
It is possible to hide (in a separate file/library) the implementation/definition of
void display_integers(const integer_range& rng)
But in the case of
template <class ForwardRange>
void display_integers(const ForwardRange& rng)
you have to provide source code to users (or at least make explicit instantiations somewhere).
Moreover, in the first case, display_integers
will be compiled only once, but in the second it will be compiled for every type of the passed range.
Also, you may have somewhere
integer_range rng;
and during lifetime of rng
you may assign ranges of different types to it:
vector<int> v;
list<int> l;
integer_range rng;
rng = v;
rng = l;
The biggest disadvantage of type erasure is its runtime cost; all operations are virtual, and cannot be inlined (easily).
P.S. another famous example of type erasure is std::function