Need iterator when using ranged-based for loops

C++C++11For LoopIterator

C++ Problem Overview


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?

C++ Solutions


Solution 1 - C++

Use the old for loop as:

for (auto it = values.begin(); it != values.end();  ++it )
{
       auto & value = *it;
       //...
}

With this, you've value as well as iterator it. Use whatever you want to use.


EDIT:

Although I wouldn't recommended this, but if you want to use range-based for loop (yeah, For whatever reason :D), then you can do this:

 auto it = std::begin(values); //std::begin is a free function in C++11
 for (auto& value : values)
 {
     //Use value or it - whatever you need!
     //...
     ++it; //at the end OR make sure you do this in each iteration
 }

This approach avoids searching given value, since value and it are always in sync.

Solution 2 - C++

Here is a proxy wrapper class to allow you to expose the hidden iterator by aliasing it to your own variable.

#include <memory>
#include <iterator>

/*  Only provides the bare minimum to support range-based for loops.
    Since the internal iterator of a range-based for is inaccessible,
    there is no point in more functionality here. */
template< typename iter >
struct range_iterator_reference_wrapper
    : std::reference_wrapper< iter > {
    iter &operator++() { return ++ this->get(); }
    decltype( * std::declval< iter >() ) operator*() { return * this->get(); }
    range_iterator_reference_wrapper( iter &in )
        : std::reference_wrapper< iter >( in ) {}
    friend bool operator!= ( range_iterator_reference_wrapper const &l,
                             range_iterator_reference_wrapper const &r )
        { return l.get() != r.get(); }
};

namespace unpolluted {
    /*  Cannot call unqualified free functions begin() and end() from 
        within a class with members begin() and end() without this hack. */
    template< typename u >
    auto b( u &c ) -> decltype( begin( c ) ) { return begin( c ); }
    template< typename u >
    auto e( u &c ) -> decltype( end( c ) ) { return end( c ); }
}

template< typename iter >
struct range_proxy {
    range_proxy( iter &in_first, iter in_last )
        : first( in_first ), last( in_last ) {}

    template< typename T >
    range_proxy( iter &out_first, T &in_container )
        : first( out_first ),
        last( unpolluted::e( in_container ) ) {
        out_first = unpolluted::b( in_container );
    }

    range_iterator_reference_wrapper< iter > begin() const
        { return first; }
    range_iterator_reference_wrapper< iter > end()
        { return last; }

    iter &first;
    iter last;
};

template< typename iter >
range_proxy< iter > visible_range( iter &in_first, iter in_last )
    { return range_proxy< iter >( in_first, in_last ); }

template< typename iter, typename container >
range_proxy< iter > visible_range( iter &first, container &in_container )
    { return range_proxy< iter >( first, in_container ); }

Usage:

#include <vector>
#include <iostream>
std::vector< int > values{ 1, 3, 9 };

int main() {
    // Either provide one iterator to see it through the whole container...
    std::vector< int >::iterator i;
    for ( auto &value : visible_range( i, values ) )
        std::cout << "# " << i - values.begin() << " = " << ++ value << '\n';

    // ... or two iterators to see the first incremented up to the second.
    auto j = values.begin(), end = values.end();
    for ( auto &value : visible_range( j, end ) )
        std::cout << "# " << j - values.begin() << " = " << ++ value << '\n';
}

Solution 3 - C++

I tried myself on this and found a solution.

Usage:

for(auto i : ForIterator(some_list)) {
    // i is the iterator, which was returned by some_list.begin()
    // might be useful for whatever reason
}

The implementation was not that difficult:

template <typename T> struct Iterator {
    T& list;
    typedef decltype(list.begin()) I;

    struct InnerIterator {
        I i;
        InnerIterator(I i) : i(i) {}
        I operator * () { return i; }
        I operator ++ () { return ++i; }
        bool operator != (const InnerIterator& o) { return i != o.i; }
    };

    Iterator(T& list) : list(list) {}
    InnerIterator begin() { return InnerIterator(list.begin()); }
    InnerIterator end() { return InnerIterator(list.end()); }
};
template <typename T> Iterator<T> ForIterator(T& list) {
    return Iterator<T>(list);
}

Solution 4 - C++

range based for loop is created as the c++ counterpart for foreach in java that allows easy iteration of array elements. It is meant for removing the usage of complex structures like iterators so as to make it simple. I you want an iterator, as Nawaz said, you will have to use normal for loop.

Solution 5 - C++

There is a very simple way of doing this for std::vector, which should also work if you are resizing the vector during the process (I'm not sure whether the accepted answer considers this case)

If b is your vector, you can just do

for(auto &i:b){
    auto iter = b.begin() + (&i-&*(b.begin()));
}

where iter will be your required iterator.

This takes advantage of the fact that C++ vectors are always contiguous.

Solution 6 - C++

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) {
    // ...
}

Solution 7 - C++

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;
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Question小太郎View Question on Stackoverflow
Solution 1 - C++NawazView Answer on Stackoverflow
Solution 2 - C++PotatoswatterView Answer on Stackoverflow
Solution 3 - C++payloadView Answer on Stackoverflow
Solution 4 - C++Ragesh ChakkadathView Answer on Stackoverflow
Solution 5 - C++pulsejetView Answer on Stackoverflow
Solution 6 - C++Hunter KohlerView Answer on Stackoverflow
Solution 7 - C++mbuschView Answer on Stackoverflow