As I work with Boost.Range, I frequently want to call a method returning an iterator_range and, from that range, instantiate a standard container. I have a couple of helpers I'd like to propose for inclusion in the Boost.Range library.
/**
* From any range compatible with Boost.Range, return an instance of any
* class with a constructor accepting a compatible iterator pair.
*/
template<class TYPE, typename RANGE>
TYPE make_from_range(const RANGE& range)
{
return TYPE(boost::begin(range), boost::end(range));
}
It would probably be appropriate to provide a non-const RANGE& overload as well.
make_from_range<CONTAINER>(range) is helpful for, e.g., passing an argument to a function accepting const CONTAINER&. But what if you want to declare a local instance of such a container?
/**
* From any range compatible with Boost.Range, instantiate any class
* with a constructor accepting a compatible iterator pair.
*/
template<class TYPE>
struct instance_from_range: public TYPE
{
template<typename RANGE>
instance_from_range(const RANGE& range):
TYPE(boost::begin(range), boost::end(range))
{}
// Again, a non-const RANGE& overload would probably be useful.
};
Usage example:
instance_from_range< std::vector<std::string> >
my_vector(function_returning_range_of_string());
Why not
vector<string> my_vector(make_from_range<vector<string> >(get_range());
?
RVO will make sure that no copies of a container are created.
If you don't want to specify vector<string> twice you can follow the approach of Boost.Assign -- create an object with a conversion to anything and let it be converted to a container.
template <class Range>
struct from_range_impl {
from_range_impl(const Range& range) : range_(range) {}
template <class Container>
operator Container() const { return Container(begin(range_), end(range_)); }
private:
const Range& range_;
};
template <class Range>
from_range_impl<Range> make_from_range(const Range& range) {
return from_range_impl<Range>(range);
}
Example:
void foo(const vector<string>& v);
iterator_range<string*> range;
foo(make_from_range(get_range(range));
vector<string> v(make_from_range(range));
Sometimes you'll still want to explicitly specify type of the container that should be created by make_from_range (for example when you pass it to an overloaded function), but you can keep both versions of make_from_range and use each of them when appropriate.
Roman Perepelitsa.