2009-01-24 8 views
20

मैंने पाया अपने आप कोकैसे मानकों के साथ एसटीडी उपयोग करने के लिए :: foreach/संशोधन

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

एक बहुत लेखन, और मैं एक foreach बयान में इस संपीड़ित करने के लिए चाहते हैं, लेकिन मुझे यकीन है कि कैसे नहीं कर रहा हूँ सुपर-वर्बोज़ के बिना param प्राप्त करने के लिए। मुझे

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

जैसी चीजें भी मिली हैं और मैं उस लड़के को भी फिर से लिखना चाहता हूं। कोई विचार?

ओह, विभिन्न कारणों से, मैं बूस्ट का उपयोग नहीं करना चाहता हूं।

उत्तर

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

धन्यवाद! दूसरे पर कोई विचार, यद्यपि? –

7

ओह, भी, विभिन्न कारणों के लिए, मैं नहीं चाहता कि बढ़ावा उपयोग करना चाहते हैं।

मान्य निर्णय, लेकिन सबसे अधिक संभावना गलत है। एसटीएल के विस्तार के रूप में बूस्ट पर विचार करें। सी ++ एक लाइब्रेरी संचालित भाषा है। यदि आप इसे ध्यान में नहीं लेते हैं, तो आपका कोड गुणात्मक रूप से कम होगा।

जबकि std::for_each का उपयोग यहां किया जा सकता है, सी ++ में लैम्ब्डा अभिव्यक्तियों की अनुपस्थिति सी ++ 0x तक यह थकाऊ हो जाती है। मैं Boost.ForEach का उपयोग करने का समर्थन करता हूं!

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

हां, यह मेरा निर्णय नहीं है कि बूस्ट का उपयोग करना है या नहीं। –

+8

शायद यह कहना चाहें कि आप * बूस्ट का उपयोग नहीं कर सकते हैं। कह रहे हैं कि आप * नहीं चाहते हैं * सिर्फ एक तर्क मांग रहे हैं ...;) – jalf

+0

@jalf * के बारे में * क्या नहीं होगा? –

4

मेरे पसंदीदा समाधान एक functor लिखने के लिए मैं क्या जरूरत है ऐसा करने के लिए आमतौर पर है:

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

private: 
    Param p; 
}; 

और फिर पाश:

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

निर्भर करता है यह इस ज्यादा आसान बना देता है इस पर आपके कितने बदलाव हैं, यह थोड़ा सा वर्बोज़ हो सकता है। हालांकि इनलाइन करने के लिए बहुत सारे विकल्प हैं। बढ़ावा :: लैम्ब्डा आपको कॉल-साइट पर आवश्यक फ़ंक्शन का निर्माण करने देगा। boost :: बाइंड (या मानक लाइब्रेरी बाइंड फ़ंक्शंस) आपको फ़ंक्शन पर पैरामीटर पैरामीटर को बाध्य करने देगा ताकि आपको इसे हर बार तर्क के रूप में आपूर्ति करने की आवश्यकता न हो।

बढ़ावा :: लैम्ब्डा शायद सबसे संक्षिप्त और लचीला दृष्टिकोण है। मैं आमतौर पर सादे मज़ेदार दृष्टिकोण का उपयोग करता हूं क्योंकि वाक्यविन्यास को याद रखना आसान है। ;)

+0

यह वही है जो मैंने किया था (और इससे बचने की उम्मीद थी) :) –

+0

एचएम, बिना बूस्ट (आउच), मुझे नहीं लगता कि आप इसे बहुत कम कर सकते हैं। कुछ मामलों में, std :: bind_ * सामान आपकी मदद कर सकता है, लेकिन कोई चमत्कारी चांदी की गोलियाँ नहीं हैं। (कम से कम lambda अभिव्यक्तियों के साथ सी ++ 0x तक) – jalf

3

अच्छी तरह से हम compilers का समर्थन करने वाले C++ 0x लैम्ब्डा expresions है जब, इस सरल और कम आक्रामक हो जाता है:

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

और दूसरा उदाहरण कुछ ऐसा नज़र हो सकता है:

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

यह बहुत दयालु है, यह g ++ पर काम नहीं करता है :(मुझे आशा है कि मैं किसी भी समय उन निर्माणों का उपयोग कर पाऊंगा ... – Arman

+0

मुझे उम्मीद है भी :) – 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) 
    ) 
); 

} 

आप नामस्थानों का उपयोग करके इसे सरल बना सकते हैं ...

0

आप जीसीसी उपयोग कर रहे हैं आप की तरह कुछ परिभाषित कर सकते हैं:

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

और इस तरह के बाद इसका इस्तेमाल:

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

मैं एक कस्टम सरणी पर इस का उपयोग, लेकिन यह एसटीडी के साथ ठीक काम करता है: वेक्टर भी।

संबंधित मुद्दे