6

मेरे पास डेमो उद्देश्यों के लिए एडीएल के लिए दो स्निपेट हैं। दोनों स्निपेट को वीसी 10, जीसीसी & आउरा सी ++ कंपाइलर्स द्वारा संकलित किया गया है, और परिणाम तीनों के लिए समान हैं।एडीएल को 'std namespace' में किसी फ़ंक्शन पर प्राथमिकता क्यों लेती है लेकिन उपयोगकर्ता द्वारा परिभाषित नेमस्पेस में फ़ंक्शन के बराबर होती है?

< 1> एक उपयोगकर्ता परिभाषित नाम स्थान के निर्देशों का उपयोग के खिलाफ ADL:

#include <algorithm> 
namespace N 
{ 
    struct T {}; 
    void swap(T,T) {} 
} 

namespace M 
{ 
    void swap(N::T,N::T) {} 
} 

int main() 
{ 
    using M::swap; 
    N::T o1,o2; 
    swap(o1,o2); 
} 

संकलित परिणाम:

error C2668: 'M::swap' : ambiguous call to overloaded function 
could be 'void M::swap(N::T,N::T)' 
or  'void N::swap(N::T,N::T)' [found using argument-dependent lookup] 

यह ADL के रूप में की उम्मीद है सामान्य देखने परिणाम पर प्राथमिकता नहीं ले करता है प्लस एडीएल द्वितीय श्रेणी का नागरिक नहीं है, एडीएल खोज परिणाम सामान्य (गैर एडीएल) unquailfied लुकअप के साथ संघीय है। यही कारण है कि हमारे पास अस्पष्टता है।

< 2> एसटीडी नाम स्थान के निर्देशों का उपयोग के खिलाफ ADL:

#include <algorithm> 
namespace N 
{ 
    struct T {}; 
    void swap(T,T) {} //point 1 
} 

namespace M 
{ 
    void swap(N::T,N::T) {} 
} 

int main() 
{ 
    using std::swap; 
    N::T o1,o2; 
    swap(o1,o2); 
} 

यह एक ठीक संकलित करता है।

परिणाम संकलक एडीएल परिणाम (यह std :: स्वैप का उदाहरण लेता है) का चयन करता है, जिसका अर्थ है 'पॉइंट 1' पर N::swap() कहा जाएगा। केवल जब 'बिंदु 1' की अनुपस्थिति में (कहें कि क्या मैं उस पंक्ति पर टिप्पणी करता हूं), संकलन इसके बजाय std::swap पर गिरावट का उपयोग करेगा।

नोट इस तरह से कई स्थानों पर std::swap को ओवरराइट करने के तरीके के रूप में उपयोग किया गया है। लेकिन मेरा सवाल यह है कि, एडीएल को 'std namespace' (case2) पर प्राथमिकता क्यों दी जाती है लेकिन उपयोगकर्ता द्वारा परिभाषित नेमस्पेस फ़ंक्शन (केस 1) के बराबर माना जाता है?

क्या सी ++ मानक में एक पैराग्राफ है जो ऐसा कहता है?

============================================== ====================================उपयोगी उत्तरों पढ़ने के बाद संपादित करें, दूसरों के लिए सहायक हो सकता है।

तो मैंने अपने स्निपेट को tweaked किया हैअब अस्पष्टता चली गई है और संकलन ओवरलोडिंग करते समय अनुपूरक रूप से Nontemplate फ़ंक्शन पसंद करते हैं!

#include <algorithm> 
namespace N 
{ 
    struct T {}; 
    void swap(T,T) {} 
} 

namespace M 
{ 
    template<class T> 
    void swap(N::T,N::T) {} 
} 

int main() 
{ 
    using M::swap; 
    N::T o1,o2; 
    swap(o1,o2); //here compiler choose N::swap() 
} 

मैंने अपने स्निपेट को भी tweaked किया है 2. बस अस्पष्टता को मजाक के लिए प्रकट करने के लिए!

#include <algorithm> 
namespace N 
{ 
    struct T {}; 

    template<class _Ty> inline 
    void swap(_Ty& _Left, _Ty& _Right) 
    { 
     _Ty _Tmp = _Move(_Left); 
     _Left = _Move(_Right); 
     _Right = _Move(_Tmp); 
    } 
} 

namespace M 
{ 
    void swap(N::T,N::T) {} 
} 

int main() 
{ 
    using std::swap; 
    N::T o1,o2; 
    swap(o1,o2); 
} 

जीसीसी और comeau दोनों अस्पष्टता कहना अपेक्षा के अनुरूप:

"std::swap" matches the argument list, the choices that match are: 
      function template "void N::swap(_Ty &, _Ty &)" 
      function template "void std::swap(_Tp &, _Tp &)" 

BTW VC10 बेवकूफ हमेशा की तरह इस एक पास ठीक है जब तक मैं 'का उपयोग कर std :: स्वैप' को दूर करते हैं।

बस थोड़ा अधिक लिखने के लिए: सी ++ अधिक भार मुश्किल हो सकता है (30+ C++ मानक पेज), लेकिन appendlix B में की वहाँ एक बहुत पठनीय 10 पेज है ...

सब अच्छा करने के लिए धन्यवाद इनपुट, अब यह स्पष्ट है।

उत्तर

9

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

+0

उल्लेखनीय बात यह है कि एडीएल * नाम लुकअप * से संबंधित है, और नाम लुकअप में "प्राथमिकता" की कोई धारणा नहीं है। –

+0

@ केरेकस्क: मुझे लगता है कि डेविड नाम लुकअप चरण के बाद बात कर रहा था जबकि ओवरलोडिंग रिज़ॉल्यूशन में, जो सबसे अच्छा मैच चुनने के बारे में है। – Gob00st

12

एक समारोह कॉल कई चरणों में होता है †:

  1. नाम लुकअप -> एक तथाकथित अधिभार सेट
    • इस हिस्से जहां ADL यदि आप होता है में उम्मीदवार कार्यों डालता है एक अयोग्य नाम लुकअप
  2. टेम्पलेट तर्क कटौती -> अधिभार सेट
  3. में प्रत्येक टेम्पलेट के लिए
  4. अधिभार संकल्प -> सबसे अच्छा मैच

आप नाम देखने वास्तव में अधिभार सेट ({N::swap, std::swap}) में दोनों swap कार्यों डाल देंगे हिस्सा 3. साथ भाग 1 भ्रमित कर रहे हैं लेने के लिए, लेकिन भाग 3 तय करेगा, जो अंत में कॉल करने के लिए एक।

अब, std::swap के बाद से एक टेम्पलेट है, और मानक का कहना है कि गैर टेम्पलेट कार्यों अधिक विशिष्ट टेम्पलेट कार्यों से जब अधिभार संकल्प कर रही है, अपने <2> कॉल N::swap हैं:

§13.3.3 [over.match.best] p1

इन परिभाषाओं को देखते हुए, एक व्यवहार्य कार्य F1 को एक अन्य व्यवहार्य फ़ंक्शन F2 की तुलना में बेहतर फ़ंक्शन माना जाता है यदि [...]

  • F1 एक गैर टेम्पलेट समारोह है और F2 एक समारोह टेम्पलेट विशेषज्ञता [...]

है † मैं इस विषय पर this excellent series के पहले तीन वीडियो सलाह देते हैं।

+0

तो, कृपया डाउनवोट पर टिप्पणी करें? – Xeo

+0

मानक संदर्भ के लिए धन्यवाद! – Gob00st

+0

@Xeo: डुनो (डाउनवोट के संबंध में), पहली वाक्य ने मुझे थोड़ा उलझन में डाल दिया, क्योंकि कंपाइलर को * सभी * फ़ंक्शंस नहीं मिलते हैं जिन्हें कॉल किया जा सकता है। नाम लुकअप केवल सबसेट ढूंढने के बारे में है। –