2011-03-15 59 views
5

मेरे पास निम्न main.cpp फ़ाइल'ऑपरेटर <<' के लिए 'std :: cout <<' में अस्पष्ट अधिभार <<

#include "listtemplate.h" 
//#include <iostream> 
using namespace std; 

int main() 
{ 
    int UserChoice; 
    cout << "Hello, World!" << endl; 
    cin >> UserChoice; 
    cout << UserChoice; 
} 

है इसके वर्तमान रूप में, सब कुछ काम करता है। मैं एक पूर्णांक दर्ज करता हूं, और वह पूर्णांक स्क्रीन पर मुद्रित होता है। हालांकि, जब मैं cout << "Hello, World!" << endl लाइन को अनजान करता हूं, तो मुझे निम्न त्रुटि मिलती है

main.cpp:10: error: ambiguous overload for ‘operator<<’ in ‘std::cout << "Hello, World!"’ 

मैं इसे #include "listtemplate.h" पर टिप्पणी करके भी काम कर सकता हूं, हैलो वर्ल्ड लाइन को असम्बद्ध करता हूं, और मुख्य में <iostream> (वर्तमान में टेम्पलेट के माध्यम से सुलभ। क्या कोई भी देख सकता है कि मैं यहां क्या खो रहा हूं?

listtemplate.h

#ifndef LISTTEMPLATE_H 
#define LISTTEMPLATE_H 
#include "list.h" 
using namespace std; 

// Default constructor 
template <class Type> 
list<Type> :: list() : Head(NULL) {} 

// Destructor 
template <class Type> 
list<Type> :: ~list() 
{ 
    Node *Temp; 
    while (Head != NULL) 
    { 
     Temp = Head; 
     Head = Head -> Next; 
     delete Temp; 
    } 
} 

// Copy constructor 
template <class Type> 
list<Type> :: list (const Type& OriginalList) 
{ 
    Node *Marker; 
    Node *OriginalMarker; 

    OriginalMarker = OriginalList.Gead; 
    if (OriginalMarker == NULL) Head = NULL; 
    else 
    { 
     Head = new Node (OriginalMarker -> Element, NULL); 
     Marker = Head; 
     OriginalMarker = OriginalMarker -> Next; 

     while (OriginalMarker != NULL) 
     { 
      Marker -> Next = new Node (OriginalMarker -> Next); 
      OriginalMarker = OriginalMarker -> Next; 
      Marker = Marker -> Next; 
     } 
    } 
} 

// Copy assignment operator 
template <class Type> 
list<Type>& list<Type> :: operator= (const list<Type>& Original) 
{ 
    Node *Marker; 
    Node *OriginalMarker; 

    // Check that we are not assigning a variable to itself 
    if (this != &Original) 
    { 
     // First clear the current list, if any 
     while (Head != NULL) 
     { 
      Marker = Head; 
      Head = Head -> Next; 
      delete Marker; 
     } 

     // Now build a new copy 
     OriginalMarker = Original.Head; 
     if (OriginalMarker == NULL) Head = NULL; 
     else 
     { 
      Head = new Node (OriginalMarker -> Element, NULL); 
      Marker = Head; 
      OriginalMarker = OriginalMarker -> Next; 

      while (OriginalMarker != NULL) 
      { 
       Marker -> Next = new Node (OriginalMarker -> Element, NULL); 
       OriginalMarker = OriginalMarker -> Next; 
       Marker = Marker -> Next; 
      } 
     } 
    } 
    return (*this); 
} 

// Test for emptiness 
template <class Type> 
bool list<Type> :: Empty() const 
{ 
    return (Head == NULL) ? true : false; 
} 

// Insert new element at beginning 
template <class Type> 
bool list<Type> :: Insert (const Type& NewElement) 
{ 
    Node *NewNode; 
    NewNode = new Node; 
    NewNode -> Element = NewElement; 
    NewNode -> Next = Head; 
    return true; 
} 

// Delete an element 
template <class Type> 
bool list<Type> :: Delete (const Type& DelElement) 
{ 
    Node *Temp; 
    Node *Previous; 

    // If list is empty 
    if (Empty()) return false; 

    // If element to delete is the first one 
    else if (Head -> Element == DelElement) 
    { 
     Temp = Head; 
     Head = Head -> Next; 
     delete Temp; 
     return true; 
    } 

    // If the list has only one element which isn't the specified element 
    else if (Head -> Next == NULL) return false; 

    // Else, search the list element by element to find the specified element 
    else 
    { 
     Previous = Head; 
     Temp = Head -> Next; 

     while ((Temp -> Element != DelElement) && (Temp -> NExt != NULL)) 
     { 
      Previous = Temp; 
      Temp = Temp -> Next; 
     } 

     if (Temp -> Element == DelElement) 
     { 
      Previous -> Next = Temp -> Next; 
      delete Temp; 
      return true; 
     } 
     else return false; 
    } 
} 

// Print the contents of the list 
template <class Type> 
void list<Type> :: Print (ostream& OutStream) const 
{ 
    Node *Temp; 
    Temp = Head; 

    while (Temp != NULL) 
    { 
     OutStream << Temp -> Element << " "; 
     Temp = Temp -> Next; 
    } 
} 

// Overloaded output operator 
template <class Type> 
ostream& operator<< (ostream& OutStream, const list<Type>& OutList) 
{ 
    OutList.Print (OutStream); 
    return OutStream; 
} 
#endif 

list.h

#ifndef LIST_H 
#define LIST_H 
#include <iostream> 
#include <cstddef> 
using namespace std; 

template <class Type> 
class list 
{ 
private: 
    struct Node 
    { 
    public: 
     Type Element; 
     Node *Next; 

     Node() : Next(NULL) {} // Default constructor 
     Node (Type Data, Node *PNode = NULL) : // Non-default constructor 
      Element (Data), 
      Next (PNode) {} 
    }; 

    Node *Head; 
public: 
    list(); 
    ~list(); 
    list (const Type& OriginalList); 
    bool Empty() const; 
    bool Insert (const Type& NewElement); 
    bool Delete (const Type& DelElement); 
    void Print (ostream& OutStream) const; 
    list& operator= (const list<Type>& Original); 
}; 

template <class Type> 
ostream& operator<< (ostream& OutStream, const Type& OutList); 
#endif 

उत्तर

8

मुझे लगता है कि समस्या यह है कि अपने शीर्षक में आप इस समारोह नमूने है कि:

template <class Type> 
ostream& operator<< (ostream& OutStream, const Type& OutList); 

इसके बजाय:

template <class Type> 
ostream& operator<< (ostream& OutStream, const list<Type>& OutList); 

आपके द्वारा प्रोटोटाइप किए गए संस्करण का कहना है कि यह operator << है जो कुछ भी प्रिंट कर सकता है, कुछ भी सूचियों की सूची नहीं। नतीजतन, जब आप लिखते हैं

cout << "Hello, world!" << endl; 

संकलक नहीं बता सकता है जो कार्य करते हैं इसे कहते चाहिए था - मानक आउटपुट समारोह या एक आप अपनी सूची में शीर्ष लेख में परिभाषित किया है।

1

घोषित:

ostream& operator<< (ostream& OutStream, const Type& OutList); 
के रूप में समारोह परिभाषा

:

ostream& operator<< (ostream& OutStream, const list<Type>& OutList) 
19

यह वास्तव में एक दिलचस्प सवाल है। मुख्य मुद्दा यह है, के रूप में दूसरों से पहले कि आप निम्न हस्ताक्षर घोषणा की है बताया है:

template <typename T> 
std::ostream& operator<<(std::ostream&, T const &); 

और वह अस्पष्टता से चलाता है, के रूप में यह एक कैच-ऑल टेम्पलेट है। लेकिन यह क्यों है कि संकलक cout में एक पूर्णांक (असंबद्ध रूप से) सम्मिलित कर सकता है लेकिन यह const char* नहीं डाल सकता है?

इसका कारण std::basic_ostream टेम्पलेट और मानक में आवश्यक निःशुल्क फ़ंक्शंस की परिभाषा में है। विशेष रूप से, टेम्पलेट क्लास basic_ostream में सदस्य फ़ंक्शन शामिल हैं जिनमें int शामिल हैं। दूसरी ओर, धाराओं में const char* का सम्मिलन एक टेम्पलेटेड मुक्त फ़ंक्शन के रूप में परिभाषित किया गया है। तीन घोषणाओं को एक साथ लाने:

namespace std { 
template <typename CharT, typename traits = char_traits<CharT> > 
class basic_ostream { 
// ... 
    basic_ostream<CharT,traits>& operator<<(int n); // [1] 
// ... 
}; 
template<class charT, class traits> // [2] 
basic_ostream<charT,traits>& operator<<(basic_ostream<charT,traits>&, const char*); 
} 
template <typename T> // [3] 
std::ostream& operator<<(std::ostream&, T const &); // user defined 

अब, जब संकलक अभिव्यक्ति std::cout << 5 का सामना करना पड़ता है, यह पता चलता है कि [1] एक गैर टेम्प्लेटेड सही मुकाबला नहीं है।यह std::cout के रूप में गैर-टेम्पलेट किया गया है basic_ostream कक्षा टेम्पलेट के ठोस तत्कालता का एक उद्देश्य है, जब संकलक उस वर्ग के सदस्यों को मानता है, तो प्रकार ठीक हो जाता है। विधि स्वयं टेम्पलेट नहीं है।

टेम्पलेट [3] एक ही उपयोग से मेल खाता है, लेकिन क्योंकि [1] टेम्पलेट नहीं किया गया है, इसे ओवरलोड रिज़ॉल्यूशन में प्राथमिकता दी जाती है, और कोई अस्पष्टता नहीं होती है।

अब, जब संकलक std::cout << "Hello world"; अभिव्यक्ति को देखता है, तो यह लुकअप करता है और यह पाता है (यह उन अन्य विकल्पों के बीच है जिन्हें मिलान नहीं किया जा सकता है और इस प्रकार छोड़ा जा सकता है) विकल्प [2] और [3]। समस्या यह है कि अब, दोनों विकल्प टेम्पलेट्स हैं, पहले को CharT = char और traits = char_traits<char> से मिलान करके हल किया जा सकता है, जबकि दूसरा T = const char* (पहला तर्क एक ठोस तत्काल प्रकार) बनाकर मिलान किया जा सकता है। कंपाइलर अपना दिमाग नहीं बना सकता है (कोई आंशिक क्रम नहीं है जो परिभाषित करता है कि इसे किस विकल्प का पालन करना चाहिए), और यह अस्पष्टता त्रुटि को ट्रिगर करता है।

प्रश्न में वास्तव में दिलचस्प बात यह है कि दोनों [1] और [2] तर्क CharT और traits मूल रूप से एक ही तरह से वे संकलक द्वारा उसी तरह से नहीं माना जाता है, पर टेम्प्लेट की गई हो रहे हैं इसका कारण यह है कि लुकअप पाता है [1] std::cout के सदस्य के रूप में, इसका मतलब है कि [1], basic_ostream<char,char_traits<char> >कंक्रीट पहले तर्क का प्रकार ज्ञात है और यह तय है। टेम्पलेट वर्ग है, फ़ंक्शन नहीं है, और क्लास इंस्टेंटेशन प्रकार को लुकअप से पहले सदस्य फ़ंक्शन पर विचार करने से पहले तय किया जाता है। दूसरी ओर, जब यह एडीएल पाता है [2] और कॉल के खिलाफ मैच करने का प्रयास करता है, basic_ostream<CharT, traits>सामान्य प्रकार है जिसे cout के प्रकार से मेल किया जा सकता है।

मुझे आशा है कि यह बहुत भ्रमित नहीं है, लेकिन मुझे लगता है कि के सूक्ष्म अंतर को देखने के कोड को जानना अच्छा लगता है।

+0

+1 अस्पष्टता क्यों है, इस बारे में महान स्पष्टीकरण! – templatetypedef

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