Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to fill STL containers by means of generate_n with index increment

Tags:

c++

lambda

stl

To fill STL containers with values that depend on their index, I usually write like the code below. Is there any way to do the same without declaring the index?

int main(){
  static int N=10;
  auto func = [](int idx){return idx*(idx+1)+1;};
  int idx = -1;
  std::list<int> lst;
  std::generate_n(std::back_inserter(lst), N, [&](){idx++; return func(idx);});
}
like image 903
orematasaburo Avatar asked Jul 11 '18 09:07

orematasaburo


People also ask

Are STL containers passed by reference?

@BjörnPollex Yes! I forgot to mention that.

How are STL containers implemented in C++?

A container is a holder object that stores a collection of other objects (its elements). They are implemented as class templates, which allows great flexibility in the types supported as elements.


4 Answers

You can move the index into the lambda capture and make the lambda mutable like this (requires C++14):

std::generate_n(std::back_inserter(lst), N,
    [&func, idx = -1] () mutable {idx++; return func(idx);});

Now you can omit the line int idx = -1;. There might be a better solution though, as sacrificing the default const qualification of the closure just to move an integer declaration from the surrounding scope into the capture isn't perfect. Still though, the scope of idx has been reduced, and if I understand your question correctly, this was the goal.

like image 62
lubgr Avatar answered Oct 22 '22 06:10

lubgr


Performance wise, this looks equivalent:

#include <list>
#include <algorithm>

int main()
{
  std::list<int> lst;
  std::generate_n(std::back_inserter(lst), 10, [&](){auto idx = lst.size(); return idx*(idx+1)+1;});
}
like image 34
YSC Avatar answered Oct 22 '22 05:10

YSC


If you can use boost, then this works

#include <algorithm>
#include <list>
#include <boost/iterator/counting_iterator.hpp>

int main()
{
    static int N = 10;
    std::list<int> lst;
    std::transform(boost::counting_iterator<int>(0), boost::counting_iterator<int>(N), std::back_inserter(lst), func);
}
like image 24
Caleth Avatar answered Oct 22 '22 07:10

Caleth


You can use static variable inside lambda function. I think it's better than calling list size function inside lambda everytime if your list size is big.

#include <iostream>
#include <algorithm>
#include <list>

int main()
{
   static int N = 10;
   std::list<int> lst;
   std::generate_n(std::back_inserter(lst),    
         N, [&](){
           static int idx = -1; 
           ++idx; 
           return idx*(idx+1)+1;
         });

   for(auto e : lst)
       std::cout << e << " ";
}
like image 36
NeutronStar Avatar answered Oct 22 '22 05:10

NeutronStar