gpt4 book ai didi

c++ - ‘std::cout << 中 ‘operator<<’ 的模糊重载

转载 作者:可可西里 更新时间:2023-11-01 18:41:24 26 4
gpt4 key购买 nike

我有以下 main.cpp文件

#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> 来使其工作。在 main 中(目前可通过模板访问。任何人都可以看到我在这里遗漏了什么吗?

列表模板.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

列表.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

最佳答案

这其实是个有趣的问题。主要问题是,正如其他人之前指出的那样,您已经声明了以下签名:

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

这会引发歧义,因为它是一个包罗万象 的模板。但为什么编译器可以(明确地)将一个整数插入到 cout 中?但它不能插入 const char*

原因在于 std::basic_ostream 的定义中标准中要求的模板和自由函数。特别是模板类 basic_ostream包含用于插入基本类型的成员 函数,包括int .另一方面,插入 const char* into streams 被定义为一个模板化的自由函数。将三个声明放在一起:

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"; ,它执行查找并找到(在无法匹配并因此被丢弃的其他选项中)选项 [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> >是第一个参数的具体已知类型并且它是固定的。模板是类,而不是函数,并且类实例化类型在查找考虑成员函数之前是固定的。另一方面,当它 ADL 找到 [2] 并尝试匹配调用时,basic_ostream<CharT, traits>是一个通用类型,可以匹配到 cout 的类型.

我希望这不会太困惑,但我认为了解相似外观代码的细微差别是件好事。

关于c++ - ‘std::cout << 中 ‘operator<<’ 的模糊重载,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5319190/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com