How to use std::foreach with parameters/modification

前端 未结 6 2247
难免孤独
难免孤独 2020-12-23 11:34

I\'ve found myself writing

for(int i=0;iDoWhatever(param);

a lot, and I\'d like to compress this into

相关标签:
6条回答
  • 2020-12-23 12:08

    If you are using GCC you can define something like:

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

    and use it after like this:

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

    I use this on a custom array but it works fine with std::vector too.

    0 讨论(0)
  • 2020-12-23 12:09

    well when we have compilers that support C++0x lambda expresions, this becomes straightforward and minimally invasive:

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

    and the second example may look like this:

    std::for_each(myvec.begin(),myvec.end(),[&](X& item){   
       if(item->IsOK())      
          myvec[i]->DoWhatever(param);
    });
    
    0 讨论(0)
  • 2020-12-23 12:19

    Oh, also, for various reasons, I don't want to use boost.

    Valid decision, but most likely the wrong one. Consider Boost as an extension to the STL. C++ is a library-driven language. If you don't take this into account, your code will be qualitatively inferior.

    While std::for_each can be used here, the absence of lambda expressions in C++ until C++0x makes this tedious. I advocate using Boost.ForEach! It makes this much easier:

    foreach (yourtype x, yourvec)
        if (x.IsOK())
            x.Whatever();
    
    0 讨论(0)
  • 2020-12-23 12:19

    My preferred solution is usually to write a functor to do what I need:

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

    And then the loop:

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

    Depending on how many variations of this you have, this might be a bit too verbose. There are plenty of options for doing it inline though. boost::lambda would let you construct the function you need at the call-site. boost::bind (or the standard library bind functions) would let you bind the parameter param to the function so you don't need to supply it as an argument every time.

    boost::lambda is probably the most concise and flexible approach. I usually use the plain functor approach because the syntax is easier to remember. ;)

    0 讨论(0)
  • 2020-12-23 12:23
    #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 讨论(0)
  • 2020-12-23 12:23
    #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)
        )
      );
    
    }
    

    You can simplify it by using namespaces...

    0 讨论(0)
提交回复
热议问题