Boost logo

Boost Users :

Subject: Re: [Boost-users] [Range] Adapt 2-iterator container constructors for Range?
From: Roman Perepelitsa (roman.perepelitsa_at_[hidden])
Date: 2008-09-24 03:15:56


2008/9/24 Nat Goodspeed <nat_at_[hidden]>

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



Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net