Potrzeba iteratora podczas korzystania z pętli for

Obecnie mogę zrobić tylko pętle z tym:

for (auto& value : values)

Ale czasami potrzebuję iteratora do wartości, zamiast referencji (z jakiegokolwiek powodu). Czy istnieje jakaś metoda bez konieczności przechodzenia przez cały wektor porównujący wartości?

Author: Flow, 2011-08-05

6 answers

Użyj starej pętli for jako:

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

Z tym, masz value jak również iterator it. Używaj tego, czego chcesz.


EDIT:

Chociaż nie polecałbym tego, ale jeśli chcesz użyć pętli opartej na zakresie for (tak, z jakiegokolwiek powodu :d), możesz to zrobić:

 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
 }

Takie podejście pozwala uniknąć wyszukiwania podanego value, ponieważ value i it są zawsze zsynchronizowane.

 64
Author: Nawaz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-06 16:07:54

Oto Klasa wrappera proxy, która pozwala na ujawnienie ukrytego iteratora poprzez aliasowanie go do własnej zmiennej.

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

Użycie:

#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';
}
 14
Author: Potatoswatter,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-08-12 02:23:14

Wypróbowałem to i znalazłem rozwiązanie.

Użycie:

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

Realizacja nie była aż tak trudna:

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);
}
 10
Author: payload,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-02-17 14:55:28

Zakres for pętla jest tworzona jako odpowiednik foreach w języku java w języku c++, który umożliwia łatwą iterację elementów tablicy. Jest on przeznaczony do usuwania użycia złożonych struktur, takich jak Iteratory, aby to uprościć. Chcę iterator, Jak powiedział Nawaz, będziesz musiał użyć normalnej pętli for.

 3
Author: Ragesh Chakkadath,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-08-05 08:15:13

Istnieje bardzo prosty sposób zrobienia tego dla std::vector, który powinien również działać, jeśli zmieniasz rozmiar wektora podczas procesu (nie jestem pewien, czy przyjęta odpowiedź uwzględnia ten przypadek)

Jeśli b jest Twoim wektorem, możesz po prostu zrobić

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

Gdzie {[3] } będzie twoim wymaganym iteratorem.

Wykorzystuje to fakt, że wektory C++ są zawsze sąsiadujące ze sobą.

 1
Author: PulseJet,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:34:33

Zróbmy to bardzo nieczysto ... Wiem, że 0x70h zmienia się wraz ze stosem, wersją kompilatora, .... Powinno być ujawnione przez kompilator, ale tak nie jest: - (

char* uRBP = 0; __asm { mov uRBP, rbp }
Iterator** __pBegin = (Iterator**)(uRBP+0x70);
for (auto& oEntry : *this) {
    if (oEntry == *pVal) return (*__pBegin)->iPos;
}
 0
Author: mbusch,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-09 09:13:30