2011-03-15 77 views
5

我有以下main.cpp文件的曖昧超載「運營商<<」中「的std ::法院<<

#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」,取消註釋的hello world線,幷包括主<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::coutbasic_ostream類模板的具體實例的一個對象,當編譯器考慮該類的成員時,該類型是固定的。該方法本身不是模板化的。

模板[3]可以匹配相同的用途,但是因爲[1]沒有模板化,所以在重載解析中優先,並且沒有歧義。

現在,當編譯器看到表達式std::cout << "Hello world";時,它執行查找並找到(其他選項無法匹配,因此被丟棄)options [2]和[3]。問題是,現在,兩個選項都是模板,第一個可以通過匹配CharT = chartraits = char_traits<char>來解決,而第二個可以通過使T = const char*(第一個參數是具體的實例化類型)匹配來解決。編譯器無法下定決心(沒有偏序來定義它應該遵循哪個選項),並且會觸發模糊性錯誤。

問題中真正有趣的一點是,儘管[1]和[2]似乎都以參數CharTtraits爲基礎進行模板化,基本上它們與編譯器不以相同的方式考慮,原因是查找找到[0123]作爲std::cout的成員,這意味着在[1]中,basic_ostream<char,char_traits<char> >具體已知的類型的第一個參數,它是固定的。模板是類,而不是函數,並且在查找考慮成員函數之前,類實例化類型是固定的。另一方面,當ADL發現[2]並試圖與呼叫匹配時,basic_ostream<CharT, traits>通用類型,其可以與cout的類型匹配。

我希望這不是太混亂,但我認爲很高興知道類似尋找代碼的細微差異。

+0

+1很好的解釋,爲什麼有歧義! – templatetypedef 2011-03-16 01:33:16