97 votes

Besoin d'un itérateur lors de l'utilisation de boucles for à distance

Actuellement, je ne peux faire que des boucles à distance avec ceci:

 for (auto& value : values)
 

Mais parfois, j'ai besoin d'un itérateur à la valeur, au lieu d'une référence (pour une raison quelconque). Existe-t-il une méthode sans avoir à parcourir tout le vecteur en comparant les valeurs?

84voto

Nawaz Points 148870

Utiliser le vieux - for boucle:

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

Avec cela, vous avez value ainsi que itérateur it. Utilisez celui que vous souhaitez utiliser.


EDIT:

Bien que je n'aurais pas recommandée, mais si vous souhaitez utiliser basés sur la plage, for boucle (ouais, Pour quelque raison que ce soit :D), alors vous pouvez faire ceci:

 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
 }

Cette approche évite de recherche donné, value, depuis value et it sont toujours synchronisés.

16voto

Potatoswatter Points 70305

Ce qu'ils auraient dû faire, c'est définir std::begin et std::end pour std::pair< T, T > , afin de vous permettre d'accéder à l'itérateur masqué.

Voici une classe wrapper de proxy vous permettant d'exposer l'itérateur masqué en l'aliasant vers votre propre variable. ( Edit : Maintenant testé! Je ne savais pas que G ++ le supportait déjà.)

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

15voto

payload Points 235

Je me suis essayé et j'ai trouvé une 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
}
 

La mise en œuvre n'était pas si difficile:

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

2voto

Ragesh Chakkadath Points 1142

La boucle for basée sur la plage est créée en tant que contrepartie c ++ pour foreach en java, ce qui permet une itération facile des éléments du tableau. Il est destiné à supprimer l'utilisation de structures complexes telles que les itérateurs afin de simplifier les choses. Si vous voulez un iterator , comme le dit Nawaz, vous devrez utiliser la boucle normale for .

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X