链表模板实现和运算符重载

Linked list template implementation and operators overloading

我对 C++ 中的模板还很陌生,目前在理解它们时遇到了一些困难。所以,有人给了我下一个使用模板的链表实现,运算符重载对我来说非常不清楚。这是代码:

#include <iostream>
using namespace std;

template<typename T> class List;

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

template <typename T>
struct Node {
    T info;
    Node<T>* next;

    Node (T x, Node<T>* n = nullptr) : info(x), next(n) {}
};

template <typename T>

class List {
    Node<T>* first, *last;
    public:
        List() {
            this->first = nullptr;
            this->last = nullptr;
        }

        List (initializer_list<T> l)
        {
            ...
        }
         ~List();

        template <typename U>
                friend istream& operator >>(istream& is, List<U>& l);  /// ***HERE***

        friend ostream& operator<< <T> (ostream&, const List<T>&);     /// ***HERE***
        void insert(T,unsigned);
};
template <typename T> List <T>::~List()
{
   ...
}

template <typename T>
istream& operator >>(istream& is, List<T>& l)
{
    Node<T>* f = l.first;
    while (f != nullptr)
    {
        is >> f->info;
        f = f->next;
    }
    return is;
}

template <typename T>
ostream& operator<< (ostream& out, const List<T>& l) {
    Node<T>* p = l.first;

    while (p != nullptr) {
        out << p->info << " ";
        p = p->next;
    }

    return out;
}
template<typename T>
void List<T>::insert(T t, unsigned x)
{
    ...
}

int main () {
}

他为什么使用 template <typename U> 来重载 >>friend ostream& operator<< <T> (我不确定我什至不明白 [=15] 右边的 <T> 是什么=] 表示).

我想您的问题的答案可以在 2.4 Friends 第 30 页的 C++ Templates: The Complete Guide 第二版中找到:

通常 operator >><< 为标准输入 std::istream 和输出流 std::ostream 超载,因此您可以从输入读取并写入抽象输出流。这可以在 class 之外完成,但如果在进程中访问的 class 成员是 private (就像两个指针 firstlast 在你的例子中)要么必须使用 setter 和 getter 为它创建一个接口,要么 在 class[=52 中将运算符声明为 friend =].通常人们会在 class 本身内部声明和定义它,但是如果出于某种原因人们希望或需要这样做,否则事情会变得有点棘手,并且 声明友元函数有两种主要方法但是之后定义它:

  • 可以声明具有不同模板参数的新函数模板

    template <typename U>
    friend istream& operator >> (istream&, List<U>&);
    

    这就是friend istream& operator >> (istream&, List<U>&);的实现方式。

  • 可以前向声明class以及输出运算符

    template<typename T> class List;
    
    template <typename T>
    ostream& operator << (ostream&, const List<T>&);
    

    然后我们将非成员函数模板的特化声明为 friend(因此 <T>)。

    friend ostream& operator << <T> (ostream&, const List<T>&);
    

    这就是friend ostream& operator << <T> (ostream&, const List<T>&);的实现方式。

在这两种情况下,您都必须按照 class.

之外的定义来跟进声明

我没有从代码片段中看到一个比另一个更喜欢一个的真正原因:在这种情况下,它们应该是相等的。我个人实际上什至不会经历前向声明任何东西的麻烦,而是在 class 本身内部声明和定义它,因为我认为它更清楚。在我看来,应尽可能避免前向声明。