Jak używać std:: foreach z parametrami / modyfikacją

I ' ve found myself writing

for(int i=0;i<myvec.size();i++)
   myvec[i]->DoWhatever(param);
Bardzo, i chciałbym to skompresować w foreach oświadczenie, ale nie jestem pewien, jak się tam dostać param bez bycia super-gadatliwym. Mam też takie rzeczy jak
for(int i=0;i<myvec.size();i++)
   if(myvec[i]->IsOK())
      myvec[i]->DoWhatever(param);
I chciałbym go też przepisać. Jakieś pomysły? Poza tym, z różnych powodów, nie chcę używać Boosta.
Author: Rex M, 2009-01-24

6 answers

#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)
                 );
}
 15
Author: Martin York,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-01-24 19:19:59
Poza tym, z różnych powodów, nie chcę używać Boosta.
Słuszna decyzja, ale najprawdopodobniej zła. Rozważ Boost jako rozszerzenie STL. C++ jest językiem opartym na bibliotekach. Jeśli nie weźmiesz tego pod uwagę, Twój kod będzie jakościowo gorszy.

Podczas gdy std::for_each może być tutaj użyte, brak wyrażeń lambda w C++ do momentu, gdy C++0x sprawia, że jest to uciążliwe. Jestem zwolennikiem używania Boost.ForEach ! To sprawia, że to dużo łatwiej:

foreach (yourtype x, yourvec)
    if (x.IsOK())
        x.Whatever();
 7
Author: Konrad Rudolph,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-01-24 19:06:27

Moim preferowanym rozwiązaniem jest zwykle napisanie functora, który zrobi to, czego potrzebuję:

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

private:
  Param p;
};

A następnie pętla:

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

W zależności od tego, ile odmian tego masz, może to być trochę zbyt gadatliwe. Istnieje wiele opcji robienia tego w linii. boost:: lambda pozwoli Ci skonstruować funkcję, której potrzebujesz na stronie wywołania. boost:: bind (lub standardowe funkcje biblioteki bind) pozwoli Ci powiązać parametr param z funkcją, więc nie musisz go dostarczać jako kłótnia za każdym razem.

Boost::lambda jest prawdopodobnie najbardziej zwięzłym i elastycznym podejściem. Zwykle używam prostego functora, ponieważ składnia jest łatwiejsza do zapamiętania. ;)

 4
Author: jalf,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-01-24 19:14:13

Cóż, kiedy mamy Kompilatory obsługujące wyrażenia lambda C++0x, staje się to proste i minimalnie inwazyjne:

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

A drugi przykład może wyglądać tak:

std::for_each(myvec.begin(),myvec.end(),[&](X& item){   
   if(item->IsOK())      
      myvec[i]->DoWhatever(param);
});
 3
Author: Rick,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-18 09:18:14
#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)
    )
  );

}

Możesz to uprościć używając przestrzeni nazw...

 3
Author: psaghelyi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-04-14 07:56:00

Jeśli używasz GCC możesz zdefiniować coś w stylu:

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

I użyj go po tak:

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

Używam tego na niestandardowej tablicy, ale działa dobrze również z std:: vector.

 0
Author: Felics,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-04-12 12:02:52