9

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?

Deduplicator
  • 43,322
  • 6
  • 62
  • 109
Thomas
  • 1,150
  • 3
  • 15
  • 33

5 Answers5

21

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()); 
Mani Zandifar
  • 1,174
  • 10
  • 14
  • Method 3 is rather handy if you want to generate an array containing the cumulative sums. Add another `partial_sum(v.begin(), v.end(), v.begin())` and for n = 5, you get {1, 3, 6, 10, 15}. – lifebalance Jan 05 '16 at 04:07
  • Note, `generate` here uses static. Put it within a function, call it multiple times and it will keep counting. Use `ValueType i = {1}; std::generate(first, last, [&i] { return i++; });` instead. – Anne van Rossum Jun 27 '17 at 17:22
10

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));
Mooing Duck
  • 59,144
  • 17
  • 92
  • 149
  • thanks, works as desired! The book is a bit unspecific with respect to that particular constructor, but later on the letters i, j are in fact used explicitly for iterators. Th. – Thomas Jan 13 '12 at 18:44
3

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;
    }
}
synthesizerpatel
  • 26,249
  • 5
  • 72
  • 89
2

C++11:

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

std::generate_n (idxs.begin (), n, [] { static int i {1}; return i++; });
genrich
  • 21
  • 1
1

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);
Brian Neal
  • 30,704
  • 7
  • 54
  • 59