2015-01-28 5 views
5

समस्या: यदि आवश्यक नहीं है, तो निम्न कोड बहुत अभिव्यक्तिपूर्ण और संक्षेप में होगा, यह इस तथ्य के लिए नहीं था कि यह संकलित नहीं होता है।इस तथ्य के आसपास कैसे काम करें कि std :: function में कोई ऑपरेटर == नहीं है?

यह संकलित नहीं करता है क्योंकि आप ऑपरेटर ==() के साथ std :: फ़ंक्शन इंस्टेंस की तुलना नहीं कर सकते हैं। और std :: find() ठीक उसी तरह करने की कोशिश करता है।

बेशक, मैं पूरी तरह से कार्यान्वयन के लिए जा सकता हूं, लेकिन जैसा कि मैं नीचे हूं और जैसा कि मैं नीचे कोड के साथ हूं, मैं जिद्दी हूं, मैं कुछ "निकटतम संभव" ढूंढ रहा हूं जो काम करता है।

कौन मुझे नीचे दिए गए कोड का एक सुंदर पुनर्लेख प्रदान कर सकता है जो वही काम करता है?

#include <functional> 
#include <vector> 

typedef std::function<bool(int)> Tester_t; 
typedef std::vector<Tester_t> TesterSet_t; 

bool Test(TesterSet_t &candidates, int foo) 
{ 
    TesterSet_t dropouts; 
    for(auto& tester : candidates) 
    { 
     if(!tester(foo))  
     { 
      droputs.push_back(tester); 
     } 
    } 

    while(!dropouts.empty()) 
    { 
     // The following line is not compiling because std::function has no operator==() 
     TesterSet_t::iterator culprit = 
      std::find(candidates.begin(), candidates.end(), dropouts.back()); 
     candidates.erase(culprit); 
     dropouts.pop_back(); 
    } 
    return !candidates.empty(); 
} 
+0

क्या आप अंतर्निहित समस्या का वर्णन कर सकते हैं जिसे आप हल करने का प्रयास कर रहे हैं? कारण 'std :: function' में '==' ऑपरेटर नहीं है क्योंकि इस तरह से फ़ंक्शंस की तुलना करने के लिए इसका कोई अर्थ नहीं है। आप कैसे निर्धारित कर सकते हैं कि दो कार्य बराबर हैं या नहीं? –

+0

इसी तरह (संभावित रूप से डुप्लिकेट): http://stackoverflow.com/questions/5847072/comparing-stdfunction –

+0

संक्षिप्त उत्तर: आपको एक ऐसी संरचना बनाना चाहिए जिसमें एक अनूठी कुंजी और 'std :: function' हो, और उसके पास वेक्टर हो उन structs। वास्तव में एक खोज कुंजी के रूप में 'std :: function' का उपयोग करने के लिए बहुत अधिक समझ नहीं आता है। [यहां देखें] (http://stackoverflow.com/questions/4430425/stdvector-of-stdfunction) –

उत्तर

10

हटाने की जरूरत है, तो आप इसके लिए std::function एस की तुलना की आवश्यकता नहीं है। मानक सी ++ इस सुविधा का उपयोग कुशलता से (रेखीय जटिलता के साथ) दो पंक्तियों में लागू किया जा सकता है:

bool Test(TesterSet_t &candidates, int foo) 
{ 
    candidates.erase(std::remove_if(candidates.begin(), candidates.end(), 
     [foo](Tester_t& f){ return !f(foo); }), candidates.end()); 
    return !candidates.empty(); 
} 
+0

अच्छा है! मुझे आश्चर्य है कि वे ऐसा क्यों कर सकते हैं और मैं नहीं कर सकता ?! ;) – BitTickler

+1

निहित वस्तुओं की कोई तुलना नहीं है, अगर भविष्यवाणी सही होती है तो यह मिटा देती है। वास्तव में –

2

आपको यहां समानता की आवश्यकता नहीं है। के रूप में तुम जाओ

for (auto it = candidates.begin(); it != candidates.end();) { 
    if (! (*it)(foo)) { 
     it = candidates.erase(it); 
    } 
    else { 
     ++it; 
    } 
} 
return !candidates.empty(); 

यह भी सवाल भले ही operator==std::function के लिए परिभाषित किया गया था में संस्करण की तुलना में तेजी हो हो जाएगा बस मिटा।

+1

पुनरावृत्ति के दौरान मिटाना आपदा के लिए एक अच्छा रास्ता है। कम से कम यह कई सालों से ऐसा था। लेकिन शायद सी ++ 11 वूडू अब यह कानूनी बनाता है? – BitTickler

+4

जब भी आप इसे ठीक से करते हैं तब तक पुनरावृत्ति करना हमेशा ठीक रहा है। –

+1

@ user2225104 यदि आप उन्हें गलत करते हैं तो बहुत सी चीजें आपदा का कारण बनती हैं। बस उन्हें करने का सही तरीका सीखें। – Barry

0

क्या तुमने कभी न उम्मीदवारों को मिटाने के लिए की जरूरत है आप लिख सकते हैं:

bool Test(TesterSet_t &candidates, int foo) 
{ 
    return std::any_of(candidates.begin(), candidates.end(), [&foo](Tester_t &tester) { 
     return tester(foo); 
    }); 
} 

अद्यतन

ठीक है, आप के रूप में अन्य लोगों ने कहा उम्मीदवारों

bool Test(TesterSet_t &candidates, int foo) 
{ 
    candidates.erase(
     std::remove_if(candidates.begin(), candidates.end(), [&foo](Tester_t &tester) { 
      return !tester(foo); 
     }), 
     candidates.end() 
    ); 
    return !candidates.empty(); 
} 
+0

मिटाना इसका हिस्सा है। और, (शेष) उम्मीदवारों को इसके लिए जाने की जरूरत है। आपका कोड लौटाता है जब यह पहली बार झूठी लौटता है। वास्तव में कोड का उद्देश्य शेष उम्मीदवारों के सेट को पतला करना है। – BitTickler

0

सरल जवाब इस मामले में std::function<...> बल्कि std::function<...> की तरह कुछ है जो एक समानता ऑपरेटरों को परिभाषित करता है का उपयोग नहींहै। function<...> के लिए एक समानता ऑपरेटर को परिभाषित करने का दृष्टिकोण निर्माण पर पता लगाने के लिए है कि वास्तविक फ़ंक्शन ऑब्जेक्ट में वास्तव में एक समानता ऑपरेटर होता है और यदि ऐसा है, तो वस्तु को तुलनीय बना दें। अन्यथा, आप या तो एक त्रुटि उत्पन्न करेंगे या आप इस विशेष कार्य ऑब्जेक्ट प्रकार को अतुलनीय होने के लिए ऑब्जेक्ट्स पर विचार करेंगे।

तत्काल अवलोकन, हालांकि, अधिकांश फ़ंक्शन ऑब्जेक्ट तुलनीय नहीं हैं! उदाहरण के लिए, लैम्ब्डा फ़ंक्शंस तुलनीय नहीं हैं और std::bind() और std::mem_fn() तुलनात्मक फ़ंक्शन ऑब्जेक्ट्स भी नहीं देते हैं। फिर, std::bind() और std::mem_fn() के लिए एक कस्टम कार्यान्वयन हो सकता है। लैम्ब्डा कार्यों को तुलनीय बनाने के लिए कोई रास्ता नहीं है जब तक में रिक्त कैप्चर होता है, तो उस स्थिति में उन्हें फ़ंक्शन पॉइंटर्स में बदल दिया जा सकता है और इसकी तुलना की जा सकती है।

समानता-जागरूक फ़ंक्शन ऑब्जेक्ट्स का कार्यान्वयन थोड़ा प्रतिक्रिया देने के लिए थोड़ा लंबा है। हालांकि, आप समानता-तुलनीय bind() और mem_fn() के लिए github पर मेरे कार्यान्वयन पर एक नज़र डाल सकते हैं। std::function<...> की समानता तुलनीय संस्करण के कार्यान्वयन के लिए this answer देखें। लैम्बडा फ़ंक्शंस तुलनीय होने के लिए वांछनीय हो सकता है, अगर उनके पास समान हस्ताक्षर हैं और सभी कैप्चर किए गए मान समानता तुलनीय हैं।

सभी ने कहा कि, यदि आप आवश्यकता से बच सकते हैं, तो शायद यह सबसे अच्छा बचा है। हालांकि, मैं कुछ उपयोग मामलों में आया हूं जहां तुलनात्मक std::function<...> इसके प्रतिबंधों के बावजूद आसान होगा (यानी, सभी फ़ंक्शन ऑब्जेक्ट्स को कवर नहीं किया जाएगा)।

+0

। यही कारण है कि मुझे लगता है कि लंबे समय से ऑटो/लैम्ब्डा/std :: फ़ंक्शन दृष्टिकोण मौलिक रूप से त्रुटिपूर्ण है। उन्हें वास्तव में एक नया आंतरिक प्रकार पेश करना चाहिए और प्रथम श्रेणी के नागरिकों के कार्य मूल्यों और कार्य संदर्भों को संदर्भित करना चाहिए। यह वास्तव में सी ++ उपयोगकर्ता समस्या नहीं है कि वे कैप्चर संदर्भ कार्यान्वयन को कैसे हल करते हैं। उस जगह के साथ, सी-- जैसे प्रयासों को सभी को एक साथ बचाया जा सकता है। – BitTickler

+0

समस्या कैप्चर से निपटने के लिए बहुत कुछ नहीं है। समस्या यह है कि आप ऑब्जेक्ट्स (या वस्तुओं के संदर्भ) को कैप्चर कर सकते हैं जो समानता तुलनीय नहीं हैं। आप इनके लिए लैम्ब्डा फ़ंक्शन चाहते हैं, उदाहरण के लिए, जब उनकी तुलना करने की आवश्यकता नहीं है। तो आप अतुल्य कार्य वस्तुओं के साथ खत्म हो जाएगा। उनके साथ कैसे निपटें (इसे एक त्रुटि मानें/उन्हें गैर-बराबर मानें) संदर्भ पर थोड़ा सा निर्भर करता है और मैं वास्तव में उस विकल्प को पसंद करता हूं जो मानक में बेक नहीं किया जाता है (यानी, इस मामले में समानता परिभाषित नहीं करता)। हालांकि, अगर कब्जे वाले सामान तुलनीय हैं, तो लैम्ब्डा कार्यों के लिए समानता अच्छी होगी। –

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