2010-02-15 6 views
7

Estoy tratando de hacer un ciclo doble sobre una lista std :: para operar en cada par de elementos. Sin embargo, estoy teniendo algunos problemas para inicializar el segundo iterador. El código que me gustaría escribir es:Cómo construir un iterador std :: list en el ciclo con el incremento

for(std::list<int>::iterator i = l.begin(); i != l.end(); ++i) { 
    for(std::list<int>::iterator j = i+1; j != l.end(); ++j) { 
     ... 
    } 
} 

que no funciona porque la lista no son iteradores de acceso aleatorio, por lo que no se puede hacer +1. Pero estoy teniendo problemas para encontrar una buena alternativa; el compilador no parece estar muy contento con std::list<int>::iterator j(i)++; que tenía alguna esperanza. Lograr lo que quiero parece que voy a tener que tener un incremento adicional incómodo que no se ajuste bien a la estructura del ciclo for.

Existen alternativas obvias (¡usar un vector, por ejemplo!) Pero me parece que debería haber alguna manera razonablemente clara de hacer esto que no estoy viendo en este momento.

Gracias de antemano por cualquier ayuda :)

Respuesta

7

¿Qué tal:

for (std::list<int>::iterator i = l.begin(); i != l.end(); ++i) { 
    for (std::list<int>::iterator j = i; ++j != l.end();) { 
     // ... 
    } 
} 
4
for(std::list<int>::iterator i = l.begin(); i != l.end(); ++i) { 
    std::list<int>::iterator j = i; ++j; 
    for(; j != l.end(); ++j) { 
     ... 
    } 
} 

De vuelta en el juego!

En realidad, este es un modismo bastante común en los algoritmos numéricos, por lo que no lo veo tan feo.

9
for(std::list<int>::iterator i = l.begin(); i != l.end(); ++i) { 
    std::list<int>::iterator j = i; 
    for(std::advance(j, 1); j != l.end(); ++j) { 
     ... 
    } 
} 
+0

'advance' no tiene valor de retorno, modifica el primer argumento. (Lo que personalmente no me gusta). Dicho esto, es fácil escribir una función 'advance_copy'. – GManNickG

+0

@GMan: reparado. Ty! – dirkgently

+0

No hay problema. Decidí ir con mi idea como una respuesta alternativa. – GManNickG

2

sólo estoy salirse de la idea que tenía en la respuesta de dirkgently:

template <typename Iter, typename Dist> 
Iter advance_copy(Iter pIter, const Dist& pOffset) 
{ 
    std::advance(pIter, pOffset); 

    return pIter; 
} 

// ... 

typedef std::list<int> int_list; 

for(int_list::iterator i = l.begin(); i != l.end(); ++i) 
{ 
    for(int_list::iterator j = advance_copy(i, 1); j != l.end(); ++j) 
    { 
    } 
} 

Usted puede hacer otra clase de funciones de utilidad también para ayudar Debe ser precisa:

// for consistency, 
template <typename Iter> 
void increment(Iter& pIter) 
{ 
    ++pIter; 
} 

template <typename Iter> 
Iter increment_copy(Iter pIter) 
{ 
    return ++pIter; 
} 

// ... 

typedef std::list<int> int_list; 

for(int_list::iterator i = l.begin(); i != l.end(); ++i) 
{ 
    for(int_list::iterator j = increment_copy(i); j != l.end(); ++j) 
    { 
    } 
} 
1

me gustaría ir fo La sugerencia de r Sean, salvo que sea un bucle while:

for (std::list<int>::iterator i = l.begin(); i != l.end(); ++i) { 
    std::list<int>::iterator j(i); 
    while(++j != l.end()) { 
     // ... 
    } 
} 
0

Si ya está utilizando Boost, entonces el método más sencillo es utilizar boost::next.

for(std::list<int>::iterator i = l.begin(); i != l.end(); ++i) 
    for(std::list<int>::iterator j = boost::next(i); j != l.end(); ++j) 
+0

Quieres decir que Boost robó mi idea. :( – GManNickG

2

El sencillo alternativa "limpio" puede basarse en el hecho de que la lista de iterador es un objeto de tipo definido por el usuario con operadores sobrecargados (en contraposición a un tipo incorporado). (Por supuesto, esto no está formalmente garantizado, pero uno puede esperar esto en función de la naturaleza del contenedor de la lista). Por esta razón, es posible aplicar el operador de prefijo ++ sobrecargado a un objeto temporal del tipo de iterador de lista.

Para lograr lo que quiere sólo tiene que crear una copia temporal de i, se incrementará con el prefijo ++ y luego usar el valor resultante para inicializar j

for(std::list<int>::iterator i = l.begin(); i != l.end(); ++i) { 
    for(std::list<int>::iterator j = ++std::list<int>::iterator(i); j != l.end(); ++j) { 
    ... 
    } 
} 

Y eso es todo. Tenga en cuenta que este truco es bastante popular y se puede encontrar en código real de vez en cuando. Tenga en cuenta también que generalmente no funcionará con std::vector porque muchas implementaciones usan punteros comunes incorporados como iteradores de vectores, pero normalmente funcionará con std::list.

Sin embargo, personalmente, realmente no usaría esto en mi código.Ya ha recibido varias buenas respuestas que lo hacen al agregar una línea adicional de código.

Cuestiones relacionadas