2009-01-24 11 views
20

que he encontrado a mí mismo escribiendoCómo usar std :: foreach con los parámetros/modificación

for(int i=0;i<myvec.size();i++) 
    myvec[i]->DoWhatever(param); 

mucho, y me gustaría para comprimir esto en una declaración foreach, pero no estoy seguro de cómo para obtener param allí sin ir súper detallado. También tengo cosas como

for(int i=0;i<myvec.size();i++) 
    if(myvec[i]->IsOK()) 
     myvec[i]->DoWhatever(param); 

y me gustaría reescribir a ese tipo también. ¿Alguna idea?

Ah, también, por varias razones, no quiero usar boost.

Respuesta

15
#include <vector> 
#include <algorithm> 
#include <functional> 

class X 
{ 
    public: 
     void doWhat(int x) {} 
     bool IsOK() const {return true;} 
}; 
class CallWhatIfOk 
{ 
    public: 
     CallWhatIfOk(int p): param(p) {} 

     void operator()(X& x) const 
     { if (x.IsOK()) {x.doWhat(param);}} 
    private: 
     int param; 
}; 

int main() 
{ 
    std::vector<X>  myVec; 

    std::for_each( myVec.begin(), 
        myVec.end(), 
        std::bind2nd(std::mem_fun_ref(&X::doWhat),4) 
       ); 


    std::for_each( myVec.begin(), 
        myVec.end(), 
        CallWhatIfOk(4) 
       ); 
} 
+0

Gracias! ¿Alguna idea sobre el segundo, sin embargo? –

7

Ah, también, por diversas razones, no quiero utilizar impulso.

Decisión válida, pero muy probablemente la incorrecta. Considere Boost como una extensión para el STL. C++ es un lenguaje dirigido por la biblioteca. Si no toma esto en cuenta, su código será cualitativamente inferior.

Mientras que std::for_each se puede utilizar aquí, la ausencia de expresiones lambda en C++ hasta C++ 0x hace que esto sea tedioso. ¡Abogo por usar Boost.ForEach! Esto hace que este mucho fácil:

foreach (yourtype x, yourvec) 
    if (x.IsOK()) 
     x.Whatever(); 
+0

Lamentablemente, no es mi decisión si usar boost. –

+8

Puede que quiera decir que * no * puede usar el refuerzo entonces. Decir que no * quiere * es solo pedir una discusión ...;) – jalf

+0

@jalf ¿Qué pasa con * no *? –

4

Mi solución preferida es por lo general para escribir un funtor a hacer lo que necesito:

struct doWhatever { 
    doWhatever(const Param& p) p(p) {} 
    void operator(MyVec v&, Param p) { 
    v.DoWhatever(param); 
    } 

private: 
    Param p; 
}; 

Y entonces el bucle:

std::for_each(myvec.begin(), myvec.end(), doWhatever(param)); 

Dependiendo sobre cuántas variaciones de esto tiene, esto podría ser un poco demasiado detallado. Sin embargo, hay muchas opciones para hacerlo en línea. boost :: lambda le permite construir la función que necesita en el sitio de llamada. boost :: bind (o las funciones de vinculación estándar de la biblioteca) le permitirían vincular el parámetro param a la función, por lo que no es necesario que lo proporcione como argumento cada vez.

boost :: lambda es probablemente el enfoque más conciso y flexible. Usualmente uso el enfoque de functor simple porque la sintaxis es más fácil de recordar. ;)

+0

Esto es lo que tenía (y esperaba evitar) :) –

+0

hm, sin impulso (ouch), no creo que puedas hacerlo mucho más corto. En algunos casos, las cosas de std :: bind_ * pueden ayudarte, pero no hay balas de plata milagrosas. (Al menos hasta C++ 0x con la adición de expresiones lambda) – jalf

3

bien cuando tenemos compiladores que admiten expresiones lambda C++ 0x, esto se convierte en sencillo y mínimamente invasiva:

std::for_each(myvec.begin(),myvec.end(),[&](X& item){ 
    item->DoWhatever(param); 
}); 

y el segundo ejemplo puede tener este aspecto:

std::for_each(myvec.begin(),myvec.end(),[&](X& item){ 
    if(item->IsOK())  
     myvec[i]->DoWhatever(param); 
}); 
+0

Eso es tan lamentable, no funciona en g ++ :(. Espero que en algún momento pueda usar esas construcciones ... – Arman

+0

Espero que sí también :) – Rick

3
#include <vector> 
#include <algorithm> 
#include <boost/bind.hpp> 
#include <boost/lambda/if.hpp> 
#include <boost/lambda/bind.hpp> 


struct A 
{ 
    bool IsOK() { return true; } 
    void DoWhatever (int param) {} 
}; 

struct B 
{ 
    bool IsOk (A * a) { return true; } 
    void DoWhatever (A * a, int param) {} 
}; 

typedef std::vector<A *> Myvec; 

void main() 
{ 
    Myvec myvec; 
    int param = 1; 
    B b; 

    // first challenge using boost::bind (fnct in the same class) 
    std::for_each (myvec.begin(), myvec.end(), 
    boost::bind (&A::DoWhatever, _1, param)); 

    // first challenge using boost::bind (fnct in an external class) 
    std::for_each (myvec.begin(), myvec.end(), 
    boost::bind (&B::DoWhatever, &b, _1, param)); 

    // second challange using boost::lambda (fnct in the same class) 
    std::for_each (myvec.begin(), myvec.end(), 
    boost::lambda::if_then(
     boost::lambda::bind (&A::IsOK, boost::lambda::_1), 
     boost::lambda::bind (&A::DoWhatever, boost::lambda::_1, param) 
    ) 
); 

    // second challange using boost::lambda (fnct in an external class) 
    std::for_each (myvec.begin(), myvec.end(), 
    boost::lambda::if_then(
     boost::lambda::bind (&B::IsOK, &b, boost::lambda::_1), 
     boost::lambda::bind (&B::DoWhatever, &b, boost::lambda::_1, param) 
    ) 
); 

} 

Puede simplificarlo mediante el uso de espacios de nombres ...

0

Si está utilizando GCC puede definir algo como:

#define foreach(element, array) \ 
    for(typeof((array).begin()) element = (array).begin(), __end_##element = (array).end();\ 
     element != __end_##element;\ 
     ++element) 

y utilizarlo después de la siguiente manera:

foreach(element, array){ 
    element->DoSomething(); //or (*element)->DoSomething() if type is already a pointer 
} 

Yo uso esta en una matriz de costumbre, pero funciona bien con std: : vector también.

Cuestiones relacionadas