2016-02-03 23 views
16

इस कोड पर विचार करें:सी ++ सदस्य समारोह सूचक परिभाषा

#include <iostream> 
#include <functional> 

struct B { 
    template <class C, class M, class T> 
    void call1(C (M::*member)(), T *instance) { 
     std::function<void()> fp = std::bind(member, instance); 
     fp(); 
    } 

    template <class C, class M, class T> 
    void call2(C (M::*member), T *instance) { 
     std::function<void()> fp = std::bind(member, instance); 
     fp(); 
    } 

    void foo() { 
     call1(&B::func, this); // works 
     call2(&B::func, this); // works 

     call1(&B::func2, this); // Error: no matching member function for call to 'call2' 
     call2(&B::func2, this); // works 
    } 

    void func() { 
     std::cout << "func\n"; 
    } 

    void func2() const volatile { 
     std::cout << "func2\n"; 
    } 
}; 

int main() { 
    B{}.foo(); 
} 

ऐसा लगता है कि बाद के संस्करण अतिरिक्त सीवी क्वालिफायर के साथ कार्यों को स्वीकार नहीं करते।

इस C (M::*member)() जैसे फ़ंक्शन सदस्य सूचक को निर्दिष्ट करने के बीच क्या अंतर है और यह C (M::*member) पसंद है?

+0

मुझे यह भी पता नहीं था कि 'सी (एम :: * सदस्य) 'मान्य वाक्यविन्यास है ... –

+0

बिंदु यह है कि' कॉल 1 'सीवी-क्वालीफायर के साथ कार्यों को स्वीकार नहीं करेगा, जबकि' कॉल 2 'अनुमति देता है। – Crossfire

+1

असंबद्ध लेकिन सदस्य कार्य को सीधे कॉल करने के बजाय 'std :: bind' का उपयोग क्यों परेशान करते हैं? '(उदाहरण -> * सदस्य)();' –

उत्तर

15

के आसान बनाने में करते हैं बस के बीच अंतर पर विचार करने के लिए:

template <class C, class M> void f(C (M::*member)()); 
template <class C, class M> void g(C (M::*member)); 

f में, member शून्य तर्क लेने और C लौटने लौटने M के एक सदस्य के कार्य करने के लिए एक सूचक है। यदि आपने इसे &B::func के साथ बुलाया है, तो संकलक M == B और C == void को घटाएगा। सीधा।

g में, member प्रकार C की M के एक सदस्य के लिए सिर्फ एक सूचक है। लेकिन, हमारे मामले में, &B::func एक समारोह है। तो यहां प्रभाव सिर्फ सूचक को छोड़ रहा है। हम M == B फिर से घटाते हैं, जबकि Cvoid() बन जाता है - अब C फ़ंक्शन प्रकार है। यह के संस्करण के संस्करण में है, जिसमें यह अधिक प्रकार के सदस्यों की अनुमति देता है। gसीवी - योग्य सदस्य functinos के खिलाफ तर्क लेने वाले कार्यों के खिलाफ, या सदस्यों के लिए पॉइंटर्स के खिलाफ, या प्रासंगिक रूप से उन कार्यों के खिलाफ मिलान कर सकता है।

के एक ओवरलोड समारोह एक उदाहरण के रूप पर विचार करें और कैसे यह अलग ढंग से निष्कर्ष निकाला जायेगा (इससे आपके प्रश्न का है, जो बाद से संपादित किया गया है में मूल समस्या दिलचस्प था, लेकिन अभी भी):

struct X { 
    void bar() { } 
    void bar(int) { } 
}; 

जब हम कार्य करें:

f(&X::bar); 

भी &X::bar हालांकि एक ओवरलोड नाम है, केवल एक ही वास्तव में C (M::*)() मेल खाता है। जिस पर M == X और C == void है। का ओवरलोड लोड करने का कोई तरीका नहीं है कि int टेम्पलेट प्रकार से मेल खाता है। तो यह अधिभारित नाम पारित करने के स्वीकार्य उपयोगों में से एक है। यह ठीक है।

हालांकि, जब हम करते हैं:

g(&X::bar); 

अब, वहाँ दो पूरी तरह से vaild कटौती कर रहे हैं। Cvoid() और void(int) दोनों हो सकता है। चूंकि दोनों मान्य हैं, कटौती संदिग्ध है, और आप संकलित करने में विफल रहते हैं - एक त्रुटि के साथ जो वास्तव में यह विशेष रूप से स्पष्ट नहीं करता है।


अब वापस अपने उदाहरण के लिए:

call1(&B::func2, this); // Error: no matching member function for call to 'call2' 
call2(&B::func2, this); // works 

&B::func2 के प्रकार void (B::*)() const volatile है। चूंकि call1 सदस्य फ़ंक्शन प्रकार पर कटौती करता है जो कोई तर्क नहीं लेता है और सीवी-योग्य नहीं है, प्रकार की कटौती बस विफल हो जाती है।उन प्रकारों को मिलान करने के लिए C या M नहीं है।

हालांकि, call2 कटौती ठीक है क्योंकि यह अधिक सामान्य है। यह सदस्य के लिए किसी भी सूचक से मेल खा सकता है। हम बस C = void() const volatile के साथ समाप्त होते हैं। यही कारण है कि यह काम करता है।

+0

क्या फ़ंक्शन पॉइंटर बनाने का कोई तरीका है, जो पैरामीटर अधिभार स्वीकार कर सकता है लेकिन सीवी-क्वालीफायरों को नजरअंदाज कर देगा? यही है, सामान्यीकृत संस्करण 'सी (एम :: * सदस्य)' तर्क स्वीकार करते हैं और सीवी-क्वालीफायरों को अनदेखा करते हैं। यदि मैं तर्क निर्दिष्ट करता हूं अर्थात 'सी (एम :: * सदस्य) (ए 1, ए 2)', मुझे इन कॉलर कार्यों को 'सी (एम :: * सदस्य) (ए 1, ए 2) कॉन्स' और' सी (एम 'के साथ अधिभारित करने की आवश्यकता है :: * सदस्य) (ए 1, ए 2) क्रमशः अस्थिर '। – Crossfire

+1

@ क्रॉसफायर बस एक प्रकार की विशेषता बनाएं ... 'टेम्पलेट संरचना is_func_const: std :: false_type {}; टेम्पलेट <कक्षा आर, कक्षा ... Args> struct is_func_const <आर (Args ...) const>: std :: true_type {}; टेम्पलेट <कक्षा आर, कक्षा ... Args> struct is_func_const <आर (Args ...) constatile>: std :: true_type {}; 'और फिर आप SFINAE का उपयोग कर सकते हैं। – Barry

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