2016-08-18 26 views
8

मैं प्रभावी आधुनिक सी ++ के पेज 91 पर उदाहरण की पुष्टि करने के लिए झुका रहा था, और मैं एक अजीब मुद्दा प्रतीत होता हूं। इस कोड कोसी ++ अस्वीकरण घोषणा टेम्पलेट कटौती

template<typename C> 
void doStuff(C& a, C& b) noexcept(noexcept(doStuff(a.front(), b.front()))) { 
    std::cout << "container version" << std::endl; 
} 

template<> 
void doStuff<int>(int& x, int& y) noexcept { 
    std::cout << "int version" << std::endl; 
} 

int main() { 
    vector<int> v1 = {1, 2, 3}; 
    vector<int> v2 = {4, 5, 6}; 
    int x = 5; 
    int y = 6; 
    doStuff(x, y); 
    doStuff(v1, v2); 
} 

मुझे

error: request for member ‘front’ in ‘a’, which is of non-class type ‘int’ void doStuff(C& a, C& b) noexcept(noexcept(doStuff(a.front(), b.front()))) {

इसलिए, यह, doStuff के शीर्ष संस्करण बुलाया जा रहा है की तरह लगता है भी a.front हालांकि() और b.front की तरह एक त्रुटि देता है() होना चाहिए चींटियों के संदर्भ में वापसी। अगर मैं कोड से सभी अस्वीकार्य घोषणाओं को हटा देता हूं, तो मुझे अपेक्षित आउटपुट मिलता है।

यह जीसीसी 5.4 के साथ है।

मैं क्या गलत कर रहा हूं?

धन्यवाद

+1

याद रखें कि टेम्पलेट्स एक compile.time विशेषता है। जब 'doStuff' फ़ंक्शन का पहला संस्करण परिभाषित किया गया है, तो कंपाइलर को' int' के लिए विशेषज्ञता के बारे में कुछ भी पता नहीं है। –

+1

समस्या भी है कि 'doStuff' को घोषित नहीं किया गया है जब इसे पहले' अस्वीकरण 'विनिर्देशन में उपयोग किया जाता है। – aschepler

उत्तर

7

समस्या है, जब इस बिंदु पर नाम लुकअप:

template<typename C> 
void doStuff(C& a, C& b) noexcept(noexcept(doStuff(a.front(), b.front()))) { 
//           ^^^^^^^ 

सिर्फ एक doStuff() मिलेगा: अपने कार्य टेम्पलेट। विशेषज्ञता अभी तक घोषित नहीं की गई है, इसलिए इसे नहीं माना जाता है।

केवल पहली बात यह है कि विशेषज्ञता से बचें। वे अजीब हैं। लेकिन फिर असली फिक्स केवल तर्क-निर्भर लुकअप उद्देश्यों के लिए एक अतिरिक्त खाली प्रकार में रहना होगा। यह noexcept देखने कि इन्स्टेन्शियशन तक मंगलाचरण में विलंब होगा करने के लिए एक आश्रित नाम जोड़ देगा:

namespace N { 
    struct adl { }; 

    void doStuff(adl, int& , int&) noexcept { 
     std::cout << "int version" << std::endl; 
    } 

    template<typename C> 
    void doStuff(adl, C& a, C& b) noexcept(noexcept(doStuff(adl{}, a.front(), b.front()))) { 
     std::cout << "container version" << std::endl; 
    } 
} 

template <class C> 
void doStuff(C& a, C& b) noexcept(noexcept(doStuff(N::adl{}, a, b))) 
{ 
    doStuff(N::adl{}, a, b); 
} 
+1

क्या 'int' अधिभार वास्तव में पहले होना चाहिए? 'अस्वीकरण' में 'doStuff'' एक आश्रित प्रतीक निर्दिष्ट नहीं है, जिसका अर्थ यह है कि इसे तत्कालता तक हल नहीं किया जाता है? – John

+0

शायद आश्चर्य की बात है, यह 'सी = std :: वेक्टर >' के लिए असफल हो जाएगा। – aschepler

+0

@aschepler फिक्स्ड। – Barry

2

खाका विशेषज्ञताओं भार के नहीं हैं। doStuff<int> के लिए आपकी विशेषज्ञता doStuff<C> का अधिभार नहीं है, यह एक विशेषज्ञता है। तो ओवरलोड रिज़ॉल्यूशन इस पर विचार नहीं करता है, अगर मूल अधिभार संकल्प द्वारा चुना जाता है, तो टेम्पलेट तत्काल इसे मानेंगे। एक अधिभार के साथ अपने विशेषज्ञता (गैर टेम्पलेट, दो int& रों लेने) की जगह

void doStuff(int& a, int& b) noexcept; 
संबंधित मुद्दे