Need iterator when using ranged-based for loops

Viewed 53867

Currently, I can only do ranged based loops with this:

for (auto& value : values)

But sometimes I need an iterator to the value, instead of a reference (For whatever reason). Is there any method without having to go through the whole vector comparing values?

8 Answers

Late as always :), but I'm here.

C++20 introduces syntax for the initializer-statement in range-based for loops. This initialization may either a simple-declaration, or an expression-statement. (The current working draft of C++23 also makes it possible to write an type-alias-declaration instead).

For a iterator, or a index, simply do something similar like the following:

std::vector<int> vec;

for (auto it = vec.begin(); auto& elem: vec) { 
   // ...
   it++;
}

for (int i = 0; auto& elem: vec) {
   // ...
   i++;
}

This fixes the issue of scope of the outside variable method which @nawaz mentioned.

To note: expressions of that sort aren't limited to only one initialization, and there are also plenty of cool things that can be done inline. Examples:

// This will only be useful for containing a complex typedef's scope inside
// a for-loop, and I would say, is a smell that your typing system is not too
// developed.
for(typedef std::vector<std::vector<int>> Matrix; Matrix& m: container) { 
    // ...
}

// Good old (or rather, very new) one liner.
for(MyType my_instance(x,y,z); auto& elem: my_instance) {
    // ...
}

Boost has a very nice range adaptor indexed:

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

The output:

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

Here we index from 1 (boost::adaptors::indexed(1)), but we could easily index from any other value also.

It is an index, not an iterator, but the most common usages of the iterator are

  • converting it into index for accessing an item in another vector.
  • reporting/returning the position where something happened.
  • accessing some neighbouring value like previous.
  • decorating the output of some kind.

All this can also be done with index directly. From the other side, passing the iterator from inside the loop somewhere else to use as exactly iterator looks like rather complicated approach.

Let's do it very dirty ... I know, the 0x70h is changing with stack-usage, compiler version, .... It should be exposed by the compiler, but it is not :-(

char* uRBP = 0; __asm { mov uRBP, rbp }
Iterator** __pBegin = (Iterator**)(uRBP+0x70);
for (auto& oEntry : *this) {
    if (oEntry == *pVal) return (*__pBegin)->iPos;
}
Related