Frage Need Iterator bei der Verwendung von entfernungsbasierten for-Schleifen


Momentan kann ich nur auf Distanz basierende Loops machen:

for (auto& value : values)

Aber manchmal brauche ich einen Iterator für den Wert anstelle einer Referenz (aus welchem ​​Grund auch immer). Gibt es eine Methode, ohne den ganzen Vektor durchgehen zu müssen, um Werte zu vergleichen?


75
2017-08-05 07:53


Ursprung


Antworten:


Benutze das Alte for Schleife als:

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

Damit hast du value sowie Iterator it. Verwenden Sie, was Sie verwenden möchten.


BEARBEITEN:

Obwohl ich das nicht empfehlen würde, aber wenn Sie range-based verwenden möchten for Schleife (ja, Warum auch immer : D), dann kannst du das machen:

 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
 }

Dieser Ansatz vermeidet Suchen gegeben value, schon seit value und it sind immer synchron.


64
2017-08-05 07:56



Hier ist eine Proxy-Wrapper-Klasse, mit der Sie den versteckten Iterator anzeigen können, indem Sie ihn Ihrer eigenen Variablen zuordnen.

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

Verwendung:

#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
2017-08-05 09:44



Ich habe mich selbst daran versucht und eine Lösung gefunden.

Verwendung:

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

Die Umsetzung war nicht so schwierig:

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
2018-02-17 11:32



bereichsbasiert  for Schleife wird als C ++ - Gegenstück für erstellt foreach in Java, das eine einfache Iteration von Array-Elementen ermöglicht. Es ist dafür gedacht, die Verwendung von komplexen Strukturen wie Iteratoren zu entfernen, um es einfach zu machen. Ich will ein iteratorWie Nawaz sagte, wirst du normal sein müssen for Schleife.


3
2017-08-05 08:15



Dafür gibt es einen sehr einfachen Weg std::vector, das sollte auch funktionieren, wenn Sie den Vektor während des Prozesses skalieren (ich bin nicht sicher, ob die angenommene Antwort diesen Fall berücksichtigt)

Ob b ist dein Vektor, du kannst es einfach tun

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

woher iter wird Ihr erforderlicher Iterator sein.

Dies nutzt den Vorteil, dass C ++ Vektoren sind immer zusammenhängend.


1
2018-04-15 06:51



Lass es uns sehr schmutzig machen ... Ich weiß, die 0x70h ändert sich mit Stack-Nutzung, Compiler-Version, .... Es sollte vom Compiler zur Verfügung gestellt werden, aber es ist nicht :-(

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

0
2018-02-09 09:13