loop instead for based c++ stl loops enumeration

c++ - instead - qt foreach



Cómo usar std:: foreach con parámetros/modificación (6)

Me he encontrado escribiendo

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

mucho, y me gustaría comprimir esto en una declaración foreach , pero no estoy seguro de cómo obtener param allí sin ser super verboso. 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.


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

Decisión válida, pero muy probablemente sea 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.

Si bien std::for_each se puede usar aquí, la ausencia de expresiones lambda en C ++ hasta C ++ 0x hace que esto sea tedioso. ¡ Boost.ForEach por usar Boost.ForEach ! Hace esto mucho más fácil:

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


Mi solución preferida suele ser escribir un functor para 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 luego el bucle:

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

Dependiendo de la cantidad de variaciones que tenga, esto podría ser un poco demasiado detallado. Sin embargo, hay muchas opciones para hacerlo en línea. boost :: lambda le permitirá 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. ;)


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 usarlo después de esta manera:

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

Lo uso en una matriz personalizada, pero también funciona bien con std :: vector.


bueno, cuando tenemos compiladores que soportan expresiones lambda de C ++ 0x, esto se vuelve directo y mínimamente invasivo:

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

y el segundo ejemplo puede verse así:

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


#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 ...


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