2011-03-15 74 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