2012-12-10 50 views
6

में std :: फ़ंक्शन हस्ताक्षर पर अधिभार कैसे करें मुझे पता है कि इस प्रश्न से पहले पूछा गया है, लेकिन काफी अनुभवी कोडर होने के बावजूद मुझे जवाब नहीं समझते हैं और इन प्रश्नों के उत्तर देने के लिए कोई तरीका नहीं दिखने के लिए स्पष्टीकरण। कोई "उत्तर" लिंक या कुछ भी नहीं है। इसके अलावा, वे सवाल काफी पुराने थे। तो, मैं सवाल फिर से पूछ रहा हूँ।सी ++

मेरे पास एक कक्षा है, जिसमें मैं + = ऑपरेटर को अधिभारित कर रहा हूं। मैं एक अधिभार एक नंगे समारोह सूचक लेना चाहते हैं, और अन्य एक std :: समारोह लेने के लिए:

void operator+=(void (*handler)()); 
void operator+=(function<void (void *, T)> handler); 

उपयोग:

MyClass a; 
a += [](){ DoSomething(); }; 
a += [](void *x, T y){ DoSomething(); }; 

दुर्भाग्य से, कोड संकलन नहीं है क्योंकि संकलक निर्धारित नहीं कर सकता कि दूसरा अधिभार पहले + = कॉल के लिए अनुपयुक्त है।

मैं इस समस्या को ठीक करने के लिए अपने ऑपरेटर + = सदस्य फ़ंक्शंस को कैसे परिभाषित करूं? मैं नहीं बदलना चाहता कि ऑपरेटरों का उपयोग कैसे किया जाता है (उदाहरण के लिए एक स्पष्ट कलाकार का उपयोग करके)। मैं उन्हें उपरोक्त प्रदर्शन के रूप में काम करना चाहता हूं।

इसके अलावा, यह निम्नलिखित अधिभार के रूप में अच्छी तरह से पाना उपयोगी होगा:

void operator+=(function<void()> handler); 

लेकिन फिर से, मैं समारोह <> टेम्पलेट के हस्ताक्षर के आधार पर अधिभार नहीं कर सकते।

अतिरिक्त उदाहरणों के लिए इस सूत्र देखें: Isn't the template argument (the signature) of std::function part of its type? (मुझे लगता है कि थ्रेड में उल्लिखित विभिन्न समाधान को लागू करने की कोशिश की, और उनमें से कोई भी संकलन होगा)

मैं की संख्या में कई वर्षों के लिए प्रोग्रामिंग किया गया है भाषाएं, लेकिन मेरे सी ++ कौशल थोड़ा जंगली हैं।

+0

** बड़ा ** प्रश्न यह है: __ आप अपने ओवरलोड 'ऑपरेटर + = '? __ – zaufi

+0

@zaufi में w/दिए गए फ़ंक्शन पॉइंटर या' std :: function' ऑब्जेक्ट को करने के लिए क्या कर रहे हैं: मैं यह देखने में असफल रहा यह प्रासंगिक है, लेकिन ठीक है। मैं इसे ईवेंट हैंडलर फ़ंक्शंस के std :: वेक्टर में जोड़ने जा रहा हूं। मैं अनिवार्य रूप से सी ++ में .NET घटनाओं को कार्यान्वित कर रहा हूं। क्योंकि शक्तियों ने अभी भी अपने सिर को इस तथ्य के चारों ओर लपेटा नहीं है कि घटनाएं और गुण हैं - क्लोजर की तरह - एक आधुनिक प्रोग्रामिंग भाषा के लिए बिल्कुल आवश्यक कार्यक्षमता। –

+0

तो, तो आपको 'std :: vector 'के साथ तत्काल एक' std :: function' के साथ तत्काल होना चाहिए (मैं' void() 'हस्ताक्षर का सुझाव देता हूं ... क्या मैं सही हूँ? – zaufi

उत्तर

3

++ जी के साथ 4.7.2 में अच्छी तरह से काम करता है कोड के बाद:

#include <functional> 
#include <iostream> 

template <typename T> 
typename std::enable_if<std::is_convertible<T, void(*)()>::value>::type 
foo(T&&) 
{ 
    std::cout << "foo(void(*)())" << std::endl; 
} 

void foo(std::function<void(void*,int)>) 
{ 
    std::cout << "foo(std::function<void(void*,int)>)" << std::endl; 
} 

int main() 
{ 
    foo([]{}); 
    foo([](void*,int){}); 
} 

समस्या std::function के निर्माता है, जो template <class F> function(F); के रूप में घोषित किया जाता है के कारण होता है। वह कन्स्ट्रक्टर सबकुछ इसके तर्क के रूप में स्वीकार करता है। यदि उस तर्क में उचित operator() नहीं है, तो कन्स्ट्रक्टर के तत्काल के दौरान एक त्रुटि उत्पन्न होती है।

दुर्भाग्यवश ओवरलोड रिज़ॉल्यूशन प्रक्रिया को किसी भी टेम्पलेट फ़ंक्शंस को तत्काल करने की आवश्यकता नहीं होती है, इसलिए संकलक का मानना ​​है कि सब कुछ std::function प्रकार में परिवर्तित किया जा सकता है।

+0

धन्यवाद, मैंने बस बिना किसी समस्या के मेरी कक्षा में इसे पाने में कामयाब रहा है; हालांकि जब मैंने टी को फंक्शन में डालने की कोशिश की तो चीजें थोड़ी बालों वाली थीं <>। ऐसा लगता है कि मुझे इसे शून्य (*)() पहले डालना है। चीयर्स। –

+0

मुझे लगता है कि मेरी मुख्य समस्या यह है कि मैंने कभी भी enable_if के बारे में नहीं सुना है और इसे समझ में नहीं आया है। मैं बेहद जागरूक था कि इससे मदद मिल सकती है (समान प्रश्नों के उत्तर देखने से), लेकिन यह नहीं पता था कि इसका उपयोग कैसे किया जाता था। मुझे अभी भी यकीन नहीं है कि यह कैसे काम करता है। –

+0

'enable_if' के बारे में कुछ जानकारी यहां मिल सकती है [http://www.boost.org/doc/libs/1_52_0/libs/utility/enable_if.html) और [यहां] (http: //en.cppreference .com/डब्ल्यू/सीपीपी/प्रकार/enable_if)। – hpsMouse

0

ठीक है, अगर आपके पास std::vector<std::function<void()>> है तो आपको ओवरलोड का समूह भी नहीं होना चाहिए। सबसे आसान तरीका एक टेम्पलेट operator+= को परिभाषित करना है, संभवतः कॉल करने योग्य ऑब्जेक्ट या फ़ंक्शन पॉइंटर्स के लिए चालू होने के लिए std::enable_if के साथ "संरक्षित" संभव है। तो लैम्बडा या कच्चे पॉइंटर्स को पास करने से आपके लिए असाइनमेंट (push_back/emplace_back) पर स्वचालित रूपांतरण होगा। पासिंग std::function बस अपेक्षित के रूप में असाइन करेगा।

+0

आप बिंदु खो रहे हैं। मैं अपने वेक्टर में "[]() {}" lambdas और "[] (शून्य *, टी) {}" lambdas दोनों जोड़ना चाहता हूं। मैं उन्हें एक सामान्य कंटेनर कक्षा में लपेटता हूं और इसे अपने वेक्टर में जोड़ता हूं। मुझे यह समझाने की कोशिश कर रहा हूं कि मुझे अलग-अलग लैम्ब्डा हस्ताक्षर की आवश्यकता नहीं है, यह आपके समय और मेरा व्यर्थ व्यर्थ है। –