Say I have a range R and I want to construct a new container from the
range R. Will I always have to repeat the expression yielding the range,
or is there a shorter way?
Example:
std::vector<int> numbers(
boost::irange(7, 42).begin(),
boost::irange(7, 42).end()
);
Note that it's just an example.
Is it possible to create a container C from a range expression R in one
step? Any helper function for this?
cheers,
Martin
_______________________________________________
Boost-users mailing list
Boost...@lists.boost.org
http://lists.boost.org/mailman/listinfo.cgi/boost-users
Hi!
Say I have a range R and I want to construct a new container from the range R. Will I always have to repeat the expression yielding the range, or is there a shorter way?
Example:
std::vector<int> numbers(
boost::irange(7, 42).begin(),
boost::irange(7, 42).end()
);
Note that it's just an example.
Is it possible to create a container C from a range expression R in one step? Any helper function for this?
For this to work I need the exact type of the range, which can be quite
annoying as far as I could tell. (Plus, I *don't want* to care what type
of the range is.)
Really, if I had C++11/auto, I wouldn't mind so much, i.e.
auto xr = get_some_range(...);
vector<int> numbers(xr.begin(), xr.end());
but I don't have an `auto` capable compiler, so spelling out the range
type for this is really crappy.
Writing a make_container function seems fiddly wrt. to the C++03
reference type of the passed range, but maybe someone can help:
template<typename C, typename R>
C make_container(R /*value? ref? const-ref?*/ range) {
return C(range.begin(), range.end());
}
and it would still be very ugly to call:
const vector<int> numbers =
make_container< vector<int> >(irange(7,42));
(Note: I did not compile/test this code!)
any ideas?
I do something like this:
template <class SinglePassRange>
boost::container::vector<typename
boost::range_value<SinglePassRange>::type> makeVector(const
SinglePassRange& rng)
{
boost::container::vector<typename
boost::range_value<SinglePassRange>::type> v(boost::begin(rng),
boost::end(rng));
return move(v);
}
and using it surprisingly often as move semantics allow for cheap
return-by-value
I guess you would also add template parameter for container type.
--
Szymon Gatner
The Lordz Games Studio
www.thelordzgamesstudio.com
On 26.08.2011 20:21, Ovanes Markarian wrote:
On Fri, Aug 26, 2011 at 2:30 PM, Martin B. <0xCDC...@gmx.at
<mailto:0xCDC...@gmx.at>> wrote:
Say I have a range R and I want to construct a new container from
the range R. Will I always have to repeat the expression yielding
the range, or is there a shorter way?
Example:
std::vector<int> numbers(
boost::irange(7, 42).begin(),
boost::irange(7, 42).end()
);
What about that:
...
integer_range<int> ir=irange(7,42);
vector<int> numbers(ir.begin(), ir.end());
For this to work I need the exact type of the range, which can be quite annoying as far as I could tell. (Plus, I *don't want* to care what type of the range is.)
Really, if I had C++11/auto, I wouldn't mind so much, i.e.
auto xr = get_some_range(...);
vector<int> numbers(xr.begin(), xr.end());
but I don't have an `auto` capable compiler, so spelling out the range type for this is really crappy.
That code is wrong. (As far as I understand C++11.)
AFAIK, you should *never*(?) explicitly move the return value as:
* The compiler is free to do so anyway. (AFAIK)
* It will prevent RVO. (AFAIK)
so I would just leave the move and do a `return v;` relying on the fact
that even my C++03 my compiler will do RVO and in-place construction of
the returned vector anyway.
cheers,
Martin
a year ago I check carefully what gcc would do by inspecting the
assembler code generated and indeed it does in-place construction. I
since then carelessly always return objects by copy, and when I
convert portion of the code that was returning by ref to return by
copy I usually do not observe any performance slow-down (although I
must say do not always check).
Nil
> Hi!
>
> Say I have a range R and I want to construct a new container from the
> range R. Will I always have to repeat the expression yielding the range,
> or is there a shorter way?
This is an interesting topic.
There is *almost* a way to do what you want, using boost assign
list_of, as per the example below. Note that I am assuming that you
want to do this efficiently, hence use the slightly less convenient
(because of the size parameter) cref_list_of function.
There are two main problems with this approach.
1. The initial element of the range has to be explictly provided to
cref_list_of. This is the 0 element in the examples below.
2. The range() function for cref_list_of completely fails when using a
boost::irange. With the exception of the initial value, the container
is filled with the final value of the irange (5 in this example). This
looks like a bug to me…
It would be really good to get boost assign enhanced to remove these
limitations. In fact I wonder if it would be particularly hard to
implement an assign::range_of function which uses the same underlying
mechanism (ie an object which is convertible to the requisite container
type).
#define BOOST_TEST_MODULE assignrange
#include <boost/test/unit_test.hpp>
#include <boost/array.hpp>
#include <boost/assign/list_of.hpp>
#include <boost/range/irange.hpp>
BOOST_AUTO_TEST_CASE(assignrange)
{
const boost::array<int, 5> input = {{ 1, 2, 3, 4, 5 }};
const std::vector<int> ivec =
boost::assign::cref_list_of<6>(0).range(input);
const boost::array<int, 6> expected = {{ 0, 1, 2, 3, 4, 5 }};
// Test passes
BOOST_CHECK_EQUAL_COLLECTIONS(ivec.begin(), ivec.end(),
expected.begin(), expected.end());
}
BOOST_AUTO_TEST_CASE(assignirange)
{
const std::vector<int> ivec =
boost::assign::cref_list_of<6>(0).range(boost::irange(1,6));
const boost::array<int, 6> expected = {{ 0, 1, 2, 3, 4, 5 }};
// Test fails!
BOOST_CHECK_EQUAL_COLLECTIONS(ivec.begin(), ivec.end(),
expected.begin(), expected.end());
std::vector<int> numbers =
boost::copy_range<std::vector<int>>( boost::irange(7,42) );
-Thorsten