6

The C++11 range-based for loop dereferences the iterator. Does that mean that it makes no sense to use it with boost::adaptors::indexed? Example:

boost::counting_range numbers(10,20);
for(auto i : numbers | indexed(0)) {
  cout << "number = " i 
  /* << " | index = " << i.index() */ // i is an integer!
  << "\n";
}

I can always use a counter but I like indexed iterators.

  • Is it possible to use them somehow with range-based for loops?
  • What is the idiom for using range-based loops with an index? (just a plain counter?)
gnzlbg
  • 7,135
  • 5
  • 53
  • 106
  • 1
    `indexed` sucks because it adds the `index()` method to the *iterator*, not the value returned from dereferencing the iterator. :/ – Xeo May 17 '13 at 18:58
  • 1
    @Xeo Indeed. Every now and then I need the index of the element in the range. First I feel bad about it. Then, I introduce a counter. If the container can be easily accessed with a plain old loop, I feel bad again and rewrite the range-based loop into a plain old loop. – gnzlbg May 17 '13 at 19:03
  • 2
    as Xeo mentioned boost indexed is not good for this. If you dont mind switching libraries theres a few C++ range libraries based on python's itertools, such as: https://github.com/ryanhaining/cppitertools/ – Cechner Jul 03 '14 at 01:00
  • 1
    Note: this is fixed since **Boost 1.56** (released August 2014); the element is indirected behind a `value_type` with `index()` and `value()` member functions. – ecatmur Jan 21 '16 at 15:14
  • 1
    @gnzlbg, are you able to correct `boost::adaptor::indexed` to `boost::adaptors::indexed`, as it took a while for me to realize that `s` was missing? – Enlico Nov 18 '19 at 10:34
  • @EnricoMariaDeAngelis done! – gnzlbg Nov 19 '19 at 15:56

3 Answers3

4

This was fixed in Boost 1.56 (released August 2014); the element is indirected behind a value_type with index() and value() member functions.

Example: http://coliru.stacked-crooked.com/a/e95bdff0a9d371ea

auto numbers = boost::counting_range(10, 20);
for (auto i : numbers | boost::adaptors::indexed())
    std::cout << "number = " << i.value()
        << " | index = " << i.index() << "\n";
ecatmur
  • 152,476
  • 27
  • 293
  • 366
0

It seems more useful when iterating over collection, where you may need the index position (to print the item number if not for anything else):

  #include <boost/range/adaptors.hpp>

  std::vector<std::string> list = {"boost", "adaptors", "are", "great"};
  for (auto v: list | boost::adaptors::indexed(0)) {
    printf("%ld: %s\n", v.index(), v.value().c_str());
  }

Prints:

0: boost
1: adaptors
2: are
3: great

Any innovation for simply iterating over integer range is strongly challenged by the classic for loop, still very strong competitor:

for (int a = 10; a < 20; a++) 

While this can be twisted up in a number of ways, it is not so easy to propose something that is obviously much more readable.

Audrius Meškauskas
  • 20,936
  • 12
  • 75
  • 93
-1

The short answer (as everyone in the comments mentioned) is "right, it makes no sense." I have also found this annoying. Depending your programming style, you might like the "zipfor" package I wrote (just a header): from github

It allows syntax like

std::vector v;
zipfor(x,i eachin v, icounter) {
   // use x as deferenced element of x
   // and i as index
}

Unfortunately, I cannot figure a way to use the ranged-based for syntax and have to resort to the "zipfor" macro :(

The header was originally designed for things like

std::vector v,w;
zipfor(x,y eachin v,w) {
   // x is element of v
   // y is element of w (both iterated in parallel)
}

and

std::map m;
mapfor(k,v eachin m)
   // k is key and v is value of pair in m

My tests on g++4.8 with full optimizations shows that the resulting code is no slower than writing it by hand.

cshelton
  • 360
  • 3
  • 8