使用std :: generate生成矩阵

时间:2013-10-07 07:16:30

标签: c++ c++11 std

使用reference。 std :: generate的行为应该等同于:

template <class ForwardIterator, class Generator>
  void generate ( ForwardIterator first, ForwardIterator last, Generator gen )
{
  while (first != last) {
    *first = gen();
    ++first;
  }
}

但是当我尝试用0-99数字填充矩阵时。相反,我得到10行0-9。那是为什么?

std::vector< std::vector<int> > m;

#ifdef GENERATE
    struct Generator{
        int seq;
        Generator():seq(0){};
        int operator()(){return seq++;};
    } generator;
#elif defined FOR_EACH
    int i = 0;
    auto increment = [&i](int &a){a = i++;};
#endif

int x = 10, y = 10;
m.resize(x);
for(auto &v : m)
{
    v.resize(y);
    #ifdef GENERATE
        generate(begin(v), end(v), generator);
    #elif defined FOR_EACH
        for_each(begin(v),end(v), increment);
    #endif
}

3 个答案:

答案 0 :(得分:3)

您也可以使用std::ref来防止复制Generator对象:

generate(begin(v), end(v), std::ref(generator));

答案 1 :(得分:2)

因为您的生成器是根据签名

复制的
void generate ( ForwardIterator first, ForwardIterator last, Generator gen )
                                                  copied ----^^^^^^^^^^^^^

即。你保留自己的副本,std::generate也可以。每当您将自己的,未经修改的generator传递给std::generate时,即每次开始使用具有其计数器0的版本时。

您需要以某种方式保留您的仿函数中的计数器并在Generator的使用中共享它,例如

struct Generator{
    int *seq;
    Generator(int &seq):seq(&seq){};
    int operator()(){return (*seq)++;};
};

....

int seq = 0;
generate(begin(v), end(v), Generator(seq));

或等效

int seq = 0;
generate(begin(v), end(v), [&seq]() { return seq++; });

答案 2 :(得分:2)

如果是std::for_each的情况,则传递lambda函数increment,它通过引用获取自动变量int i = 0;。对于每次调用for_each,它都会创建一个新的increment仿函数,但i不会重置,只会递增;因此,您会看到值是连续的。 lambda函数(i)的内存在其自己的域之外,即在父函数main中。

如果您拥有自己的generate功能,则资源位于结构内,即重新初始化Generator::seq。对于generate的每次调用,都会创建一个新的Generator;它的构造函数将seq初始化为0,每次都重置计数。

#ifdef GENERATE
int i = 0;       // lives in main
struct Generator {
    int &seq;
    Generator(int &i):seq(i) { }
    int operator()() { return seq++; }
} generator(i);
#else

这应该有效,因为Generator的内存部分现在处于更高的水平。