2

A little hard to phrase in a question so I will use an example. Lets say I do:

generate(myvec.begin(), myvec.end(), func())

Can I have it so that func() can read the index that generate is up to such that:

int func()
{
   if(index<2)
       return 1;
   else
       return 2;
}

such that myvec[0]=1, myvec[1]=1, myvec[2]=2, myvec[3]=2,..., myvec[N]=2?

tshepang
  • 12,111
  • 21
  • 91
  • 136
postelrich
  • 3,274
  • 5
  • 38
  • 65

3 Answers3

6

The short answer is "no, not directly". It can create its own variable that should track with the index, but (in a case like this) there's simply no access to the index itself.

Under the circumstances, I'd almost certainly just use std::fill twice:

std::fill_n(myVec.begin(), 2, 1);
std::fill(myVec.begin()+2, myVec.end(), 2);

Shorter, and simpler.

Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
  • Furthermore I don't see any guarantees concerning the order in which the function calls are made by `std::generate`. – juanchopanza Feb 12 '13 at 00:23
  • well right now I'm using fill 5 times. I made a simplified example but I am filling a vector with structs that I need to initialize to about 5 different initial values for the struct and wanted to get it down to one line. – postelrich Feb 12 '13 at 01:23
  • @riotburn: In a case like that, you could start with (for example) an array of structs that each define a value and a length, then define a small algorithm that walks through those and sets values in the array accordingly. – Jerry Coffin Feb 12 '13 at 03:18
3

Yes, if you use a function object as the generator (as juan points out, it is questionable whether this solution is guaranteed to work by the standard! Exercise caution and use Jerry's method.):

class mygenerator {
 public:
  mygenerator() : hits(0) {}

  int operator()() {
      hits++; 
      return (hits <= 2 ? 1 : 2);
  }

 private:
  int hits;
} 

...

mygenerator mg1;
std::generate(myvec.begin(), myvec.end(), mg1);
us2012
  • 16,083
  • 3
  • 46
  • 62
  • 2
    I'm not sure `std::generate` is *guaranteed* to be invoked in a particular order. – juanchopanza Feb 12 '13 at 00:12
  • @juan A valid concern, but the example given at cplusplus.com ( http://www.cplusplus.com/reference/algorithm/generate/ ) seems to suggest so. But admittedly I haven't checked the standard. – us2012 Feb 12 '13 at 00:13
  • You are right! I thought it was guaranteed to go from `vec.begin()` to `vec.end()` sequentially, but I can't see to find a reference to that behavior in the standard. – Nik Bougalis Feb 12 '13 at 00:14
  • ... and indeed, the standard seems to take no stance on this issue. I would consider this function to be fairly useless though if it did not do this sequentially. – us2012 Feb 12 '13 at 00:16
  • Indeed, the standard says nothing, so I wouldn't bank on it. In the case of `std::for_each` for example, it explicitly says that the order is sequential, first to last. – juanchopanza Feb 12 '13 at 00:20
  • @juan and everyone else who may be interested, I have created a new Q on this issue: http://stackoverflow.com/questions/14823732 – us2012 Feb 12 '13 at 00:52
  • @us2012 so in your solution, its creating an instance of mygenerator which increments hits each time it is called. I would write my function within operator() overloading function?? – postelrich Feb 12 '13 at 01:18
  • @juanchopanza I think we can safely assume that this is a bug in the standard. `generate` is utterly useless if without this guarantee, and it’s generally understood to work like this. Heck, there’s plenty of code out there which *requires* this behaviour for correctness (not an argument itself, but this makes all but sure that no library will ever implement it non-sequentially). – Konrad Rudolph Feb 12 '13 at 11:07
  • @KonradRudolph I agree completely. I was surprised not to find any such guarantee in the standard. I had been assuming the sequential behaviour too. – juanchopanza Feb 12 '13 at 11:12
  • I tried testing it out to see if generate fills the vector in order. I did this by using us2012's example above except I changed the () function to return hits. I then did a for loop to output the vector and it was all in order. I don't if that makes it guaranteed but does seem like generate fills in order – postelrich Feb 12 '13 at 23:32
  • @Konrad There are some interesting points about this issue at question 14823732, it seems the standard committee intended it to be this way so that the generation may be parallelized, even if that means that it can only be used for 'dumb' generators that supply some kind of random object. – us2012 Feb 13 '13 at 00:54
  • @riotburn It will work like that with most current standard libraries, but there is no guarantee. This basically means: Use it for your toy project, but don't put it in your aviation control software or your algorithmic trading software ;) – us2012 Feb 13 '13 at 00:55
0
class funkygen 
{
  int index;

public:
  funkygen() 
    : index(0)
  { }

  int operator()() 
  { 
    if(t < 2)
      t++;

    return t; 
  }
};

/* other code */

funkygen f;

std::generate(myvec.begin(), myvec.end(), f);

As juanchopanza pointed out in a comment on another answer, the elements of vec are not guaranteed to be accessed in a particular sequential order. The only guarantee is that every item will be accessed exactly once.

Nik Bougalis
  • 10,495
  • 1
  • 21
  • 37