2013-04-22 8 views
12

नीचे कोड का संदर्भ लें:निर्देश सी में घोषणा की अदला-बदली का उपयोग कर बनाम का उपयोग कर ++

#include <algorithm> 

namespace N 
{ 

    template <typename T> 
    class C 
    { 
    public: 
     void SwapWith(C & c) 
     { 
      using namespace std; // (1) 
      //using std::swap; // (2) 
      swap(a, c.a); 
     } 
    private: 
     int a; 
    }; 

    template <typename T> 
    void swap(C<T> & c1, C<T> & c2) 
    { 
     c1.SwapWith(c2); 
    } 

} 

namespace std 
{ 

    template<typename T> void swap(N::C<T> & c1, N::C<T> & c2) 
    { 
     c1.SwapWith(c2); 
    } 

} 

जैसा कि ऊपर लिखा है, कोड दृश्य स्टूडियो 2008/2010 पर संकलन नहीं है। त्रुटि है:

'void N::swap(N::C<T> &,N::C<T> &)' : could not deduce template argument for 'N::C<T> &' from 'int'. 

हालांकि, अगर मैं (1) और असम्बद्धता (2) टिप्पणी करता हूं, तो यह ठीक संकलित होगा। using namespace std और using std::swap के बीच क्या अंतर है जो इस व्यवहार को बताता है?

+4

यह एक दायरा मुद्दा प्रतीत होता है। नियम है (यदि मैं गलत नहीं हूं) तो यह हमेशा सबसे स्थानीय दायरे का उपयोग करेगा। तो यह 'std :: swap' के बजाय' N :: swap' का उपयोग करेगा, भले ही आपके पास 'नामस्थान std' – andre

+10

बीटीडब्लू का उपयोग कर रहा हो, कोड खराब हो गया है, और कार्यक्रम में अपरिभाषित व्यवहार है। आप 'std' नेमस्पेस, केवल विशेषज्ञता के लिए फ़ंक्शन टेम्पलेट * अधिभार * नहीं जोड़ सकते हैं। –

+0

इसके अलावा, यह स्वैप कैसे काम करता है, जहां तक ​​मैं कह सकता हूं कि यह एक अनंत लूप है। – andre

उत्तर

18

पहला मामला एक का उपयोग कर के निर्देश (using namespace X) है, और क्या यह मतलब है कि नाम स्थान X से नाम, नियमित रूप से देखने के लिए उपलब्ध हो जाएगा X के पहले आम नाम स्थान और वर्तमान क्षेत्र में है। इस मामले में, ::N और ::std का पहला आम नेमस्पेस पूर्वजों :: है, इसलिए उपयोग निर्देश std::swap केवल तभी उपलब्ध होगा जब लुकअप :: पर पहुंच जाए।

समस्या यह है कि जब लुकअप शुरू होता है तो यह फ़ंक्शन के अंदर दिखाई देगा, फिर कक्षा के अंदर, फिर N के अंदर और इसमें ::N::swap मिलेगा। चूंकि संभावित अधिभार का पता चला है, इसलिए नियमित लुकअप बाहरी नामस्थान :: पर जारी नहीं है। क्योंकि ::N::swap एक ऐसा फ़ंक्शन है जो संकलक एडीएल (तर्क निर्भर आचरण) करेगा, लेकिन मौलिक प्रकारों के लिए संबंधित नामस्थानों का सेट खाली है, जिससे कोई अन्य अधिभार नहीं लाएगा। इस बिंदु पर लुकअप पूर्ण हो जाता है, और ओवरलोड रिज़ॉल्यूशन शुरू होता है। यह कॉल के साथ वर्तमान (सिंगल) ओवरलोड से मिलान करने का प्रयास करेगा और int से ::N::C पर कनवर्ट करने का तरीका ढूंढने में विफल रहेगा और आपको त्रुटि मिल जाएगी।

दूसरी ओर एक उपयोग घोषणा (using std::swap) वर्तमान संदर्भ में इकाई की घोषणा प्रदान करता है (इस मामले में फ़ंक्शन के अंदर)। लुकअप को std::swap तुरंत मिलेगा और ::std::swap के साथ नियमित लुकअप बंद कर देगा और इसका उपयोग करेगा।

2

नोट: मैंने नेमस्पेस std में अपनी स्वैप परिभाषा को हटा दिया है। यह यहां प्रासंगिक नहीं है। यहां तक ​​कि इसके साथ ही कोड में भी वही समस्याएं होंगी।


यह using directive (using namespace std) और usingdeclaration (using std::swap)

Microsoft के बीच शासन मतभेद को देखने की वजह से है का कहना है

तो एक स्थानीय चर है नामस्थान चर के समान नाम, नामस्थान चर छिपा हुआ है। वैश्विक चर के रूप में एक ही नाम के साथ नामस्थान वैरिएबल होना एक त्रुटि है।

#include<iostream> 

namespace T { 
    void flunk(int) { std::cout << "T";} 
} 

namespace V { 
    void flunk(int) { std::cout << "V";} 
} 


int main() { 
    using T::flunk; // makes T::flunk local 
    // using V::flunk; // makes V::flunk local. This will be an error 
    using namespace V; // V::flunk will be hidden 
    flunk(1); 
} 

इस के अनुसार, की वजह से अपने

template <typename T> 
void swap(C<T> & c1, C<T> & c2) 

std::swap छिपा हो जाएगा जब आप

using namespace std; 

का उपयोग तो केवल swap टेम्पलेट कटौती के लिए उपलब्ध N::swap है और यह काम नहीं करेगा int एस क्योंकि यह template class तर्क के रूप में अपेक्षा करता है।

लेकिन नहीं जब

using std::swap; 

इस मामले में यह स्थानीय परिभाषा के बराबर हो जाता है। और बाहर की समस्या के साथ इस्तेमाल किया जा सकता है।

+1

पोस्ट किया गया त्रुटि संदेश ऐसी कोई अस्पष्टता का उल्लेख नहीं करता है। यह स्पष्ट है कि यह केवल एक 'स्वैप' पर विचार कर रहा है। –

+1

जब तक संकलक ' 'में' स्वैप' देख सकता है, तब तक उसका कोड संकलित होना चाहिए। अन्य दो श्रेणी SFINAE के अंतर्गत आते हैं, और बस विचार नहीं किया जाता है (मामले में जहां वे दिखाई दे रहे हैं)। –

+1

@JamesKanze हां लेकिन उपरोक्त लुकअप के नियमों के अनुसार पहले स्थान पर SFINAE के लिए उपयोग करने के लिए कोई अन्य स्वैप नहीं है। ** केवल एक ** दृश्य स्वैप है। – stardust

8

स्पष्ट कारण यह है कि एक उपयोग घोषणा और निर्देश का उपयोग अलग-अलग प्रभाव पड़ता है। घोषणा का उपयोग नाम को वर्तमान दायरे में तुरंत प्रस्तुत करता है, इसलिए using std::swap नाम स्थानीय दायरे में प्रस्तुत करता है; लुकअप यहां रुक जाता है, और आपको मिलने वाला एकमात्र प्रतीक std::swap है। इसके अलावा, यह तब होता है जब टेम्पलेट परिभाषित किया जाता है, इसलिए बाद में नामस्थान std में घोषणाएं नहीं मिलीं।निम्नलिखित लाइन में, केवलswap कि विचार किया जाएगा एक <algorithm> में परिभाषित किया गया है, के साथ साथ (नाम स्थान N में एक इस प्रकार,) ADL से जोड़े जाते हैं। (लेकिन कुलपति के साथ यह सच ++ है? संकलक सही ढंग से नाम देखने को लागू नहीं करता, इसलिए कौन जानता है।)

एक का उपयोग कर के निर्देश निर्दिष्ट करता है कि नाम दिखाई देगा "के रूप में यदि" वे निकटतम नाम स्थान संलग्नित में घोषित किया गया निर्देश और मनोनीत नामस्थान दोनों; आपके मामले में, वैश्विक नामस्थान। और यह वास्तव में नामों को पेश नहीं करता है; यह बस नाम लुकअप को प्रभावित करता है। जो एक निर्भर प्रतीक (या हमेशा, वीसी ++ के मामले में) के मामले में साइट पर होता है।

क्यों आपके पास यह विशेष त्रुटि संदेश है: शायद वीसी ++ के साथ कोई समस्या है, क्योंकि निश्चित रूप से आपके कोड में कोई गैर-कटौती करने योग्य संदर्भ नहीं हैं। लेकिन कंपाइलर के बावजूद, दोनों रूपों के समान व्यवहार होने की अपेक्षा करने का कोई कारण नहीं है।

+1

+1। * क्या यह वीएस में सच है? * कार्यान्वयन गलत है कि इसमें टेम्पलेट परिभाषा और तत्काल बिंदु (जीसीसी और सीसी के कई संस्करणों के समान) के बीच की घोषणाएं भी शामिल होंगी, लेकिन इसके अलावा इसे सही भी मिलेगा इस मामले में एक (वहां कई अन्य मामले हैं जहां यह नहीं होगा :) –

+1

@ डेविडरोड्रिगुएज़-ड्राईबीस एमएस नाम लुकअप का एक संस्करण लागू करता है जो आम था _before_ C++ 98 अपनाया गया था। तब से उन्होंने स्पष्ट रूप से कुछ इसे अनुकूलित कर लिया है, क्योंकि मूल संस्करण को नामस्थान से पहले परिभाषित किया गया था। 'नेमस्पेस एक्स का उपयोग कैसे करें' और 'x का उपयोग करके;' इस संस्करण में व्याख्या की गई है किसी का अनुमान है। (और उनके लिए मानक लागू करने के लिए 20 साल तक पर्याप्त नहीं है?) –

+1

@ जेम्ससांज एमएसवीसी दो चरणों के नाम लुकअप को सही ढंग से कार्यान्वित नहीं करता है, दूसरे चरण में अपरिवर्तनीय नामों के लिए लुकअप में देरी से। उदाहरण देखें यह [प्रश्न] (http://stackoverflow.com/questions/6273176/what-exactly-is-broken-with-microsoft-visual-cs-two-phase-template-instanti) यह समस्या यहां खेलने में प्रवेश नहीं करनी चाहिए AFAICS । – TemplateRex

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