2010-12-02 11 views
7

Hay personas felices trabajando con boost y Qt. En mi proyecto actual "incrustado" tengo que usar clases de contenedores de fabricación casera. OK, suficiente queja.Implementación de Foreach en C++, el enfoque de un pobre Pobre

He tratado de poner en práctica un foreach fácil y autónomo de esa manera:

#define ForEachString(S,C) TString S;\ 
     for (int i=0; i<C.GetSize() && (!!(&(S=C[i]))); ++i ) 

Se itera a través de una lista de cadenas que tiene métodos GetSize (op) [] y. Por ejemplo:

TStringList tables; 
ForEachString(table, tables) 
{ 
    //do sth. with tab. 
} 

De causa, lo feo es que cada tipo de contenedor requiere su propia macro. Por lo tanto, mi pregunta: ¿Es posible hacerlo contenedor independiente y aún autónomo (todas las cosas necesarias dentro de la definición de macro)?

Saludos, Valentin

+7

La respuesta es "sí", y la explicación se puede encontrar [aquí] (http://www.artima.com/cppsource/foreach.html). –

+0

Simplemente siga los nombres de los métodos similares a STL. – werehuman

+2

No lo haga, no es estándar y no ayuda mucho a la legibilidad, y puede ocultar problemas como las definiciones duplicadas –

Respuesta

6

Tal vez podría parametrizar el tipo T:

#define ForEach(T,S,C) T S;\ 
    for (int i=0; i<C.GetSize() && (!!(&(S=C[i]))); ++i ) 

TStringList tables; 
ForEach(TString, table, tables) 
{ 
    //do sth. with tab. 
} 
+0

OK, parece ser el enfoque más pragmático. –

+0

Esta no es una expresión única, como señala Talagrand. Use '#define ForEach (T, S, C) para (TS, int i = 0; i

+1

Meh, [BOOST_FOREACH] (http://stackoverflow.com/questions/4339589/foreach-implementation-in-ca-poor-mans-approach/4339813#4339813) es más fresco, ya que evita un parámetro innecesario. – Brian

2

La macro es peligrosa. Considere:

if (<condition>) 
    ForEachString(table, tables) 
    { 
     // do something 
    } 

Además, S se coloca dentro del alcance envolvente. Por lo tanto, no puede tener dos llamadas ForEachString en el mismo bloque.

Si usted tiene un compilador bleeding-edge, range-based for-loops son parte de C++ 0x

Una vez más, con C++ 0x, podría reemplazar TString S; con decltype(C[0]) S;

O, simplemente, hacer la parte Tipo de la macro:

#define ForEachString(T, S, C) T S; ... 
+0

Gracias por consejos. Sin embargo, su ejemplo causa un error de compilación, por lo que no es tan peligroso. Dos 'foreach' en el mismo alcance irían si los primeros parámetros tuvieran nombres diferentes. Desafortunadamente, C++ 0x no se usa en el proyecto. –

2

las bibliotecas Boost tienen una implementación de un foreach-como macro llamada BOOST_FOREACH la que hace precisamente esto. Es independiente del contenedor y también puede trabajar en matrices en bruto y cadenas tipo C. La implementación no es nada menos que terrorífica (muchas máquinas locas de plantilla para la introspección de tipo), pero el resultado neto es rápido, delgado, malo y ampliamente utilizado. Puede encontrar más información sobre este here.

Espero que esto ayude!

-1

Si su objetivo al crear esta macro es aprender, le recomiendo que lea la explicación de Eric Niebler sobre cómo implementar foreach, señalada por Johannes Schaub - litb (this). Se detallan todos los inconvenientes que se encuentran al tratar de resolver este problema.

Si su principal preocupación es obtener una macro foreach en funcionamiento, la función está documentada y enviada a Boost por Eric Niebler como BOOST_FOREACH.

Wiki de la comunidad, ya que estoy repitiendo lo que dijo Johannes.

+0

-1: Por favor, lea primero. Boost "no se puede usar" en muchos proyectos (por ejemplo, muchos automotrices). La razón más oficial es que no es estable. Sospecho que la verdadera razón es que muchos líderes de proyecto no están lo suficientemente familiarizados con el impulso. –

4

recomendaría éste

#define ForEachString(S,C) \ 
    if(bool _j_ = false) ; else 
    for (int _i_ = 0; _i_ < C.GetSize() && !_j_; ++_i_, _j_ = !_j_) 
     for(S = C[_i_]; !_j_; _j_ = true) 

TStringList tables; 
ForEachString(TString table, tables) 
{ 
    //do sth. with table 
} 

son necesarias las acciones extrañas con _j_ para no romper break dentro del bucle.Los mejores nombres de uso como _i_ y _j_ para no interferir con las variables de bucle local del usuario.

+0

¿Es el segundo bucle for solo para obtener el siguiente valor en S? De hecho, parece ser una mejor solución, ya que (!! (& (S = C [i]))) podría devolver false si el contenedor contenía punteros y si los 0-pointers eran válidos. En este caso, la iteración se detendría :-((En mi caso, op [] devuelve const refs, por lo que no consideré este escenario primero) –

0
#define MY_CONTAINER(a, b) a b; \ 
    typedef a::iterator b##_itr; 
#define for_each(itr, a) for(a##_itr itr = a.begin(); itr != a.end(); ++itr) 

MY_CONTAINER(vector<int>, vnVec); 
vnVec.push_back(2); 
vnVec.push_back(3); 
vnVec.push_back(10); 

for_each(itr, vnVec) 
    cout << *itr << endl; 
Cuestiones relacionadas