[Range] Adapt 2-iterator container constructors for Range?

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()); Perhaps instance_from_range might be more controversial because of the recommendation not to subclass standard containers. My thought is that once the (nearly trivial) constructor has executed, we can completely disregard the subclass. I've used it in a context where instance_from_range<CONTAINER> is "sliced" to the CONTAINER itself. Though these are small enough to recreate on demand, they're useful enough that I'd like to have them available everywhere. I hope others might find them helpful too.

2008/9/24 Nat Goodspeed <nat@lindenlab.com>
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.

Roman Perepelitsa wrote:
2008/9/24 Nat Goodspeed <nat@lindenlab.com>
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. I've been using this for years: #ifndef const_from_range_hpp #define const_from_range_hpp
#include <boost/range.hpp> #include <algorithm> #include <boost/numeric/ublas/vector.hpp> #include <boost/multi_array.hpp> namespace detail { template<typename cont_t, typename range> struct construct_from_range_impl { cont_t operator() (range const& r) { return cont_t (boost::begin (r), boost::end (r)); } }; template<typename T, typename range> struct construct_from_range_impl<boost::numeric::ublas::vector<T>, range> { typedef typename boost::numeric::ublas::vector<T> ret_t; ret_t operator() (range const& r) { ret_t v (boost::size (r)); std::copy (boost::begin (r), boost::end (r), v.begin()); return v; } }; template<typename T, typename range> struct construct_from_range_impl<boost::multi_array<T,1>, range> { typedef typename boost::multi_array<T,1> ret_t; ret_t operator() (range const& r) { ret_t v (r); return v; } }; } template<typename cont_t, typename range> cont_t inline construct_from_range (range const& r) { return detail::construct_from_range_impl<cont_t,range>() (r); } #endif

Nat Goodspeed skrev:
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.
http://www.boost.org/doc/libs/1_36_0/libs/range/doc/utility_class.html#copy_... -Thorsten

Thorsten Ottosen wrote:
Nat Goodspeed skrev:
template<class TYPE, typename RANGE> TYPE make_from_range(const RANGE& range);
http://www.boost.org/doc/libs/1_36_0/libs/range/doc/utility_class.html#copy_...
*blush* Thanks. I don't know why that didn't jump out at me when I looked through the documentation. Perhaps a brief usage example would have caught my attention more successfully. I'm still interested in the problem of declaring a local instance of a standard container without having to restate its type. I'd be happy with either Roman's approach or my own suggestion, but I do think the library would benefit from the addition of some such feature.

Nat Goodspeed skrev:
Thorsten Ottosen wrote:
Nat Goodspeed skrev:
template<class TYPE, typename RANGE> TYPE make_from_range(const RANGE& range);
http://www.boost.org/doc/libs/1_36_0/libs/range/doc/utility_class.html#copy_...
*blush* Thanks. I don't know why that didn't jump out at me when I looked through the documentation. Perhaps a brief usage example would have caught my attention more successfully.
I'm still interested in the problem of declaring a local instance of a standard container without having to restate its type. I'd be happy with either Roman's approach or my own suggestion, but I do think the library would benefit from the addition of some such feature.
I think that would be worthwhile. Romans suggestion seems elegant. Unfortunately, I don't have the time to implement/test/update the docs, (It takes some time before all these things are updated properly). but if you provide these as patches, and make a post on the dev list, I can manage to include it. If its possible to overload copy_range, I would prefer that. If you don't have the time, I'll put it on my todo list. best regards -Thorsten
participants (4)
-
Nat Goodspeed
-
Neal Becker
-
Roman Perepelitsa
-
Thorsten Ottosen