2015-02-26 9 views
5

निम्न कोड संकलित क्यों नहीं करता है, और जब मैं कक्षा ए में कन्स्ट्रक्टर से पहले स्पष्ट कीवर्ड हटा देता हूं, तो यह संकलित करता है?ओवरलोड रिज़ॉल्यूशन में "स्पष्ट" कन्स्ट्रक्टर का प्रभाव

विजुअल स्टूडियो 2013 का उपयोग करना:

enum E { e1_0, e1_1 }; 

template<typename T> 
struct A 
{ 
    A() {} 
    explicit A(unsigned long) {} 
    A(T) {} 
}; 

struct B 
{ 
    B() {} 
    B(E) {} 
}; 


void F(B) {}; 
void F(A<short>) {}; 

void test() 
{ 
    F(e1_0); 
} 

त्रुटि:

1>------ Build started: Project: exp_construct_test, Configuration: Debug Win32 ------ 
1> exp_construct_test.cpp 
1>e:\exp_construct_test\exp_construct_test.cpp(23): error C2668: 'F' : ambiguous call to overloaded function 
1>   e:\exp_construct_test\exp_construct_test.cpp(19): could be 'void F(A<short>)' 
1>   e:\exp_construct_test\exp_construct_test.cpp(18): or  'void F(B)' 
1>   while trying to match the argument list '(E)' 
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ========== 

संपादित करें: मैं बजना डाउनलोड किया है और बजना-सीएल जो दोनों ही मामलों के लिए त्रुटि की सूचना के साथ संकलित। इसलिए टिप्पणियों में बताया गया है, अस्पष्टता A<short>(short) और B(E) के बीच है।

तो शायद वीसी ++ में एक बग है, जब मैं को A(unsigned long) से हटा देता हूं, तो संकलक किसी भी अस्पष्टता को बढ़ाने के बजाय बी (ई) चुनने के द्वारा चुनता है। क्या कोई मानक अनुपालन के रूप में क्लैंग व्यवहार की पुष्टि कर सकता है, और वीसी ++ छोटी गाड़ी के रूप में?

G(e1_0); 

जो किसी भी त्रुटि को उठाने नहीं करता है:

मैं

void G(E) {}; 
void G(short) {}; 

और इस तरह जी के लिए एक कॉल गयी। यहां क्यों G(E) prefferred है, और उम्मीदवारों के मामले में A<short>::A(short) और B::B(E), वे संदिग्ध हैं?

समाप्ति संपादित

धन्यवाद --joja

+2

अगर मैं 'स्पष्ट' को हटा देता हूं, तो यह संकलित नहीं होता है, जो इसे भी नहीं करना चाहिए। संदिग्ध कॉल 'ए :: ए' नहीं बल्कि 'एफ' के लिए है। ध्यान दें कि 'ए :: ए (टी) '' स्पष्ट' नहीं है, इस प्रकार 'एफ' को कॉल संदिग्ध है। यदि आप * ए :: ए (टी) 'के लिए' स्पष्ट 'जोड़ते हैं, तो यह उस रूपांतरण को नियंत्रित करेगा और कोड संकलित होगा। – 5gon12eder

+0

एक कन्स्ट्रक्टर के सामने स्पष्ट कीवर्ड उस प्रकार की ऑब्जेक्ट को केवल एक पैरामीटर के साथ तत्काल तत्काल होने से रोकता है जो कि कन्स्ट्रक्टर तर्क के रूप में कार्य करेगा। जब आप ए के कन्स्ट्रक्टर से 'स्पष्ट' को हटाते हैं, तो आप 'शून्य एफ (ए )' को पास करके एक सरल बना सकते हैं, जो कि एफ (ई 1_0) – Prismatic

+0

@ 5gon12eder कर रहा है, आप किस कंपाइलर का उपयोग कर रहे हैं? वीएस2013 में यह 'स्पष्ट' के बिना संकलित करता है। मुझे पता है कि संदिग्ध कॉल 'एफ' है, लेकिन इसका कारण 'e1_0' का एक प्रकार है जो' एफ 'का अधिभार स्वीकार करता है। जब 'स्पष्ट' हटा दिया जाता है, तो संकलक रूपांतरण करने के लिए 'बी (ई)' चुनता है और 'एफ (बी)' कॉल करता है। मैंने यह सुनिश्चित करने के लिए 'स्पष्ट' जोड़ा, कि मैं निश्चित रूप से कन्स्ट्रक्टर का उपयोग नहीं करता, जो कि मेरे असली कोड में केवल एक विशेष मामला है। मेरी राय में, 'स्पष्ट' का उपयोग करके कंपाइलर को बी (ई) रूपांतरण का उपयोग करने के लिए और भी मार्गदर्शन करना चाहिए और 'एनम ई' को 'हस्ताक्षरित लंबे' पदोन्नति पर विचार न करें। – joja

उत्तर

3

के बाद अपने उदाहरण एक के विभिन्न रूपों पर नजर डालते हैं।

  1. मूल उदाहरण f(e0) पर कॉल करना।

    enum E {e0, e1}; 
    
    template<typename T> 
    struct A 
    { 
        A(); // (1) 
        explicit A(unsigned long); // (2) 
        A(T); // (3) 
    }; 
    
    struct B 
    { 
        B(); // (4) 
        B(E); // (5) 
    }; 
    
    void f(A<short>); // (6) 
    void f(B); // (7) 
    
    void g(E); // (8) 
    void g(short); // (9) 
    

    तीन संभावनाएं

    • एक unsigned long करने के लिए e0 कन्वर्ट के अलावा, (2) और फोन अधिभार (6) इसमें से एक A<short> बनाने निर्माता के माध्यम से,
    • short करने के लिए e0 कनवर्ट करते हैं, एक बनाने A<hort> कन्स्ट्रक्टर (3) और कॉल ओवरलोड (6) और
    • e0 से कन्स्ट्रक्टर के माध्यम सेबनाएं (5) और कॉल ओवरलोड (7)

    पहला विकल्प लागू नहीं है क्योंकि (2) explicit है। शेष दो में उपयोगकर्ता द्वारा परिभाषित रूपांतरण शामिल है जिसे समान रूप से अच्छा माना जाता है और किसी के पक्ष में कोई भी नहीं लिया जाता है। कॉल संदिग्ध है और कार्यक्रम खराब हो गया है।

  2. चलिए कन्स्ट्रक्टर से explicit हटा दें और f(e0) पर कॉल करें।

    template<typename T> 
    struct A 
    { 
        A(); // (1) 
        A(unsigned long); // (2) 
        A(T); // (3) 
    }; 
    
    struct B 
    { 
        B(); // (4) 
        B(E); // (5) 
    }; 
    

    तीन विकल्प, एक ही लेकिन इस बार रहने के सभी तीन लागू होते हैं और कॉल (और भी अधिक) है अस्पष्ट और कार्यक्रम बीमार का गठन किया।

  3. चलिए दोनों रचनाकार explicit बनाते हैं और f(e0) पर कॉल करते हैं।

    template<typename T> 
    struct A 
    { 
        A(); // (1) 
        explicit A(unsigned long); // (2) 
        explicit A(T); // (3) 
    }; 
    
    struct B 
    { 
        B(); // (4) 
        B(E); // (5) 
    }; 
    

    यह यह असंभव परोक्ष एक A<short> निर्माण करने के लिए और कॉल स्पष्ट रूप से अधिभार (5) को संदर्भित करता है बनाता है।

  4. के B के निर्माता भी कर explicit और f(e0) कहते हैं।

    template<typename T> 
    struct A 
    { 
        A(); // (1) 
        explicit A(unsigned long); // (2) 
        explicit A(T); // (3) 
    }; 
    
    struct B 
    { 
        B(); // (4) 
        explicit B(E); // (5) 
    }; 
    

    इस बार, तीन रूपांतरण पथों के कोई भी लागू क्योंकि हर एक एक explicit निर्माता के माध्यम से जाना होगा। f का कोई अधिभार नहीं है जो लागू है और कार्यक्रम खराब है।

  5. कॉल g(e0)

    • कॉल अधिभार (8) किसी भी रूपांतरण के बिना या
    • एक short करने के लिए e0 बदलने और अधिभार (9) फोन:

      हम यहाँ दो संभावनाएं है।

    इन दोनों में से, पहला विकल्प स्पष्ट रूप से अनुकूल है क्योंकि इसमें रूपांतरण शामिल नहीं है। कॉल अस्पष्ट है। (यहां तक ​​कि अगर निर्माता (5) explicit नहीं है।)

ध्यान दें कि डिफ़ॉल्ट कंस्ट्रक्टर्स (1) और (4) वास्तव में कुछ भी इस चर्चा में योगदान नहीं है। जीसीसी 4.9.1 के साथ परीक्षण, सभी पांच उदाहरण अपेक्षित व्यवहार करते हैं।

+0

धन्यवाद, @ 5gon12eder नहीं चाहिए। मेरे पास कुछ टिप्पणियां हैं: - प्वाइंट 2 .: कन्स्ट्रक्टर (2) ** के साथ ** स्पष्ट नहीं है, न तो विजुअलसी में, न ही क्लैंग मुझे तीन संभावित ओवरलोड की सूचना मिली है। - प्वाइंट 1: स्पष्ट (2) स्पष्ट, कॉलिंग f (e0) मुझे कॉल करने की उम्मीद है (5) जिसे केवल उपयोगकर्ता परिभाषित कन्स्ट्रक्टर रूपांतरण, ई -> बी (ई) का उपयोग किया जाता है, क्योंकि (3) की आवश्यकता होती है अधिक कदम: ई -> लघु -> (लघु)। - तो आप पुष्टि करते हैं, विज़ुअल सी ++ बग्गी है जब यह बिंदु 2 के उदाहरण को संकलित करता है। बिना किसी त्रुटि संदेश को उठाए और चुपचाप बी (ई) को बुला रहा है? – joja

+0

@joja ** विज्ञापन बिंदु 1: ** यह आपके लिए सहज महसूस हो सकता है लेकिन जहां तक ​​मैं कह सकता हूं, मानक में कोई नियम नहीं है जो इन रूपांतरणों में से किसी एक के मुकाबले बेहतर है, इसलिए कॉल संदिग्ध है। ** विज्ञापन बिंदु 2: ** मैं यह दावा करने में भाग नहीं पाऊंगा कि मेरे पास एक कंपाइलर तक पहुंच नहीं है, लेकिन मुझे विश्वास है कि मेरा तर्क और जीसीसी का व्यवहार यहां सही है। शायद एक और उन्नत भाषा वकील इस मुद्दे पर अधिक अधिकार के साथ आएगा और टिप्पणी करेगा। – 5gon12eder

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