Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Initialization of std::vector<unsigned int> with a list of consecutive unsigned integers

I want to use a special method to initialize a std::vector<unsigned int> which is described in a C++ book I use as a reference (the German book 'Der C++ Programmer' by Ulrich Breymann, in case that matters). In that book is a section on sequence types of the STL, referring in particular to list, vector and deque. In this section he writes that there are two special constructors of such sequence types, namely, if Xrefers to such a type,

X(n, t) // creates a sequence with n copies of t
X(i, j) // creates a sequence from the elements of the interval [i, j)

I want to use the second one for an interval of unsigned int, that is

std::vector<unsigned int> l(1U, 10U);

to get a list initialized with {1,2,...,9}. What I get, however, is a vector with one unsigned int with value 10 :-| Does the second variant exist, and if yes, how do I force that it is called?

like image 230
Thomas Avatar asked Jan 13 '12 18:01

Thomas


5 Answers

there are at least three ways that you can do that. One was mentioned earlier by Brian

//method 1
generate(v.begin(), v.end(), [] { static int i {1}; return i++; });     

You can also use std::iota if you are using c++11

//method 2
iota(v.begin(), v.end(), 1);

Or instead you can initialize your container with 1s and then do a partial sum on that. I don't think anybody will use this third method anyway :)

//method 3
vector<int> v(n, 1);                                                     
partial_sum(v.begin(), v.end(), v.begin()); 
like image 95
Mani Zandifar Avatar answered Nov 01 '22 03:11

Mani Zandifar


A non-boost way to do this with a self-incrementing iterator.

#include <vector>
#include <iostream>
#include <algorithm>

static int NUM_ITEMS = 10;

class gen_range {
    public:
        gen_range(int i) { idx = i; }
        int operator()() { return (idx++); };

    int idx;
};

int main() {

    std::vector<int> x(NUM_ITEMS);
    std::generate_n(x.begin(), NUM_ITEMS, gen_range(0));

    for (int i=0; i < x.size(); i++) {
        std::cout << x[i] << std::endl;
    }
}
like image 35
synthesizerpatel Avatar answered Nov 01 '22 04:11

synthesizerpatel


C++11:

std::vector<int> idxs (n);

std::generate_n (idxs.begin (), n, [] { static int i {1}; return i++; });
like image 22
genrich Avatar answered Nov 01 '22 04:11

genrich


Reread the paragraphs near there describing what each of the parameters are. Specifically, it should mention that i and j are not values, but iterators. This constructor is very commonly used to make copies of other types of containers. If you want to get a sequence of values, the Boost library provides a counting iterator, that does exactly what you want.

std::vector<unsigned int> numbers(
     boost::counting_iterator<unsigned int>(0U),
     boost::counting_iterator<unsigned int>(10U));
like image 10
Mooing Duck Avatar answered Nov 01 '22 04:11

Mooing Duck


No, that variant does not exist. The second constructor initializes a vector from two iterators that point into another sequence.

Here is an example of the "two-iterator" constructor in action:

int fill_data[4] = { 1, 2, 3, 4 };
std::vector<int> v(fill_data, fill_data + 4);
like image 1
Brian Neal Avatar answered Nov 01 '22 03:11

Brian Neal