Pertanyaan Butuh iterator ketika menggunakan loop berbasis-rang untuk


Saat ini, saya hanya dapat melakukan loop berbasis jarak dengan ini:

for (auto& value : values)

Tapi kadang-kadang saya membutuhkan iterator untuk nilai, bukan referensi (Untuk alasan apa pun). Apakah ada metode tanpa harus melalui seluruh nilai perbandingan vektor?


75
2017-08-05 07:53


asal


Jawaban:


Gunakan yang lama for loop sebagai:

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

Dengan ini, Anda sudah value serta iterator it. Gunakan apa pun yang ingin Anda gunakan.


EDIT:

Meskipun saya tidak akan merekomendasikan ini, tetapi jika Anda ingin menggunakan rentang berbasis for lingkaran (ya, Untuk alasan apa pun : D), maka Anda dapat melakukan ini:

 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
 }

Pendekatan ini menghindari pencarian yang diberikan value, sejak value dan it selalu sinkron.


64
2017-08-05 07:56



Di sini adalah kelas pembungkus proxy yang memungkinkan Anda untuk mengekspos iterator tersembunyi dengan menjadikannya sebagai variabel Anda sendiri.

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

Pemakaian:

#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



Saya mencoba sendiri dalam hal ini dan menemukan solusinya.

Pemakaian:

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

Pelaksanaan tidak terlalu sulit:

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



rentang berdasarkan  for loop dibuat sebagai mitra c ++ untuk foreach di java yang memungkinkan iterasi elemen array yang mudah. Ini dimaksudkan untuk menghapus penggunaan struktur kompleks seperti iterator sehingga membuatnya sederhana. Saya menginginkan sebuah iterator, seperti kata Nawaz, Anda harus menggunakan normal for lingkaran.


3
2017-08-05 08:15



Ada cara yang sangat sederhana untuk melakukan ini std::vector, yang seharusnya juga berfungsi jika Anda mengubah ukuran vektor selama proses (saya tidak yakin apakah jawaban yang diterima mempertimbangkan kasus ini)

Jika b adalah vektor Anda, Anda bisa melakukannya

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

dimana iter akan menjadi iterator Anda yang diperlukan.

Ini mengambil keuntungan dari fakta itu C + + vektor selalu berdekatan.


1
2018-04-15 06:51



Ayo kita lakukan sangat kotor ... Saya tahu, 0x70h berubah dengan stack-usage, versi compiler, .... Ini harus diekspos oleh kompilator, tetapi tidak :-(

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