Need iterator when using ranged-based for loops

前端 未结 6 1952
失恋的感觉
失恋的感觉 2020-11-29 19:34

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

for (auto& value : values)

But sometimes I need an iterator to the value, instea

相关标签:
6条回答
  • 2020-11-29 20:02

    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.

    0 讨论(0)
  • 2020-11-29 20:04

    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';
    }
    
    0 讨论(0)
  • 2020-11-29 20:04

    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);
    }
    
    0 讨论(0)
  • 2020-11-29 20:04

    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;
    }
    
    0 讨论(0)
  • 2020-11-29 20:06

    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.

    0 讨论(0)
  • 2020-11-29 20:16

    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.

    0 讨论(0)
提交回复
热议问题