[range] What's the best way to initialize a new container from a range?
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? cheers, Martin
Hi! On Fri, Aug 26, 2011 at 2:30 PM, Martin B. <0xCDCDCDCD@gmx.at> wrote:
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?
What about that: #include <boost/range/irange.hpp> #include <vector> using namespace std; using namespace boost; int main() { integer_range<int> ir=irange(7,42); vector<int> numbers(ir.begin(), ir.end()); return 0; } Regards, Ovanes
On 26.08.2011 20:21, Ovanes Markarian wrote:
On Fri, Aug 26, 2011 at 2:30 PM, Martin B. <0xCDCDCDCD@gmx.at <mailto:0xCDCDCDCD@gmx.at>> wrote:
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?
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. 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? cheers, Martin
2011/8/29 Martin B. <0xCDCDCDCD@gmx.at>:
On 26.08.2011 20:21, Ovanes Markarian wrote:
On Fri, Aug 26, 2011 at 2:30 PM, Martin B. <0xCDCDCDCD@gmx.at <mailto:0xCDCDCDCD@gmx.at>> wrote:
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?
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 29.08.2011 14:41, Szymon Gatner wrote:
2011/8/29 Martin B.<0xCDCDCDCD@gmx.at>:
On 26.08.2011 20:21, Ovanes Markarian wrote:
On Fri, Aug 26, 2011 at 2:30 PM, Martin B.<0xCDCDCDCD@gmx.at <mailto:0xCDCDCDCD@gmx.at>> wrote:
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?
I do something like this:
... { ... v(boost::begin(rng), boost::end(rng));
return move(v); }
and using it surprisingly often as move semantics allow for cheap return-by-value
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
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.
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 Martin, On 29 August 2011 13:15, Martin B. <0xCDCDCDCD@gmx.at> wrote:
On 26.08.2011 20:21, Ovanes Markarian wrote:
On Fri, Aug 26, 2011 at 2:30 PM, Martin B. <0xCDCDCDCD@gmx.at <mailto:0xCDCDCDCD@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.
If you don't care about the type of range, you could always try: BOOST_AUTO( xr, get_some_range(...) ); vector<int> numbers( xr.begin(), xr.end() ); http://www.boost.org/doc/libs/1_47_0/doc/html/typeof/refe.html#typeof.auto Cheers, Darren
On 2011-08-26 12:30:42 +0000, Martin B. said:
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()); }
Den 26-08-2011 14:30, Martin B. skrev:
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?
std::vector<int> numbers = boost::copy_range<std::vector<int>>( boost::irange(7,42) ); -Thorsten
participants (7)
-
Alastair Rankine
-
Darren Garvey
-
Martin B.
-
Nil Geisweiller
-
Ovanes Markarian
-
Szymon Gatner
-
Thorsten Ottosen