2015-03-27 14 views
12

आश्चर्यजनक रूप से नीचे कोड संकलित करता है और विभिन्न प्रकार के कंपाइलरों और संस्करणों पर त्रुटि के बिना चलता है।एंडल (std :: cout) संकलित क्यों करता है

#include <iostream> 

int main() { 
    endl(std::cout); 
    return 0; 
} 

Ideone link

यह कैसे संकलित करता है? मुझे यकीन है कि वहाँ वैश्विक क्षेत्र में है कोई endl क्योंकि जब तक using प्रयोग किया जाता है

std::cout << endl; 

की तरह एक कोड विफल हो जाएगा वरना आप std::endl की जरूरत है।

+0

[नामस्थानों के साथ कंपाइलर के दिलचस्प व्यवहार] के समान [http://stackoverflow.com/q/25976267/1708801) –

उत्तर

23

इस व्यवहार को argument dependent lookup या कोएनिग लुकअप कहा जाता है। यह एल्गोरिदम संकलक को केवल स्थानीय दायरे को न देखने के लिए बताता है, बल्कि नामस्थान जिसमें अयोग्य फ़ंक्शन कॉल की तलाश करते समय तर्क के प्रकार होते हैं।

पूर्व के लिए:

namespace foo { 
    struct bar{ 
    int a; 
    }; 

    void baz(struct bar) { 
    ... 
    } 
}; 

int main() { 
    foo::bar b = {42}; 
    baz(b); // Also look in foo namespace (foo::baz) 
    // because type of argument(b) is in namespace foo 
} 

प्रश्न पाठ में संदर्भित किया जाता है कोड का टुकड़ा के बारे में:

endl या std::endlstd नाम स्थान as following में घोषित किया जाता है:

template< class CharT, class Traits > 
std::basic_ostream<charT,traits>&  endl(std::basic_ostream<CharT, Traits>& os); 

या

std::ostream& endl (std::ostream& os); 

और cout या std::coutdeclared as

extern std::ostream cout; 

तो बुला std::endl(std::cout); बिल्कुल ठीक है।

अब जब एक बस endl(std::cout); कहता है, क्योंकि तर्क cout के प्रकार std namespace से है, अयोग्य माना जाता है कि एक समारोह endlstd नाम स्थान में खोजा गया है और यह सफलतापूर्वक पाया जाता है और इस बात की पुष्टि एक समारोह है और इस तरह योग्य समारोह std::endl के लिए एक कॉल होने के लिए से बना।


अतिरिक्त पठन:

  1. GOTW 30: Name Lookup

  2. Why does 'std::endl' require the namespace qualification when used in the statement 'std::cout << std::endl;", given argument-dependent lookup?

2

यह रास्ता धारा manipulators काम करते हैं। मैनिपुलेटर ऐसे कार्य हैं जो ऑपरेटर < < को तर्क के रूप में पास करते हैं। फिर ऑपरेटर के भीतर उन्हें बस बुलाया जाता है।

तो तुम समारोह की तरह

template <class charT, class traits> 
basic_ostream<charT,traits>& endl(basic_ostream<charT,traits>& os); 

घोषित है और आप ऑपरेटर < < करने के लिए अपने सूचक गुजरती हैं। और ऑपरेटर इस तरह

ostream& ostream::operator << (ostream& (*op)(ostream&)); 

कुछ घोषित अंदर समारोह called.like

return (*endl)(*this); 

इस प्रकार जब आप रिकॉर्ड

std::cout << std::endl; 

देखना है तो std::endl समारोह सूचक है कि करने के लिए पारित हो जाता है है तर्क के रूप में operator <<

रिकॉर्ड में

std::endl(std::cout); 

नामस्थान उपसर्ग से पहले नाम endl इस मामले में क्योंकि छोड़ा जा सकता है संकलक तर्क आश्रित लुक का प्रयोग करेंगे। इस प्रकार यह रिकॉर्ड

endl(std::cout); 

सफलतापूर्वक संकलित होगा।

लेकिन अगर तो कोष्ठक में समारोह नाम संलग्न करने ADL नहीं किया जाता है और निम्नलिखित रिकॉर्ड

(endl)(std::cout); 

संकलित नहीं होंगे।

+1

मुझे लगता है कि सवाल यह है कि फ़ंक्शन-कॉल फ़ॉर्म पर 'std ::' की आवश्यकता क्यों नहीं है –

+0

@ मैट मैकनब मैं पोस्ट को फिर से पढ़ता हूं और ऐसा लगता है कि आप सही हैं। :) –

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