Перегрузка оператора << для двусвязного списка

Рейтинг: -1Ответов: 1Опубликовано: 23.02.2023

Пытаюсь перегрузить оператор << для двусвязного списка через дружественную функцию, результат:

Ошибка C2280 "std::basic_ostream<char,std::char_traits>::basic_ostream(const std::basic_ostream<char,std::char_traits> &)": предпринята попытка ссылки на удаленную функцию DoubleLinkedList"

template<typename T>
std::ostream& operator<<(std::ostream& os, DoubleLinkedList<T>& list) 
{
    for (int i = 0; i < list.size_; i++)
    {
        os<< '[' << list[i] << "] ";
    }
}

Полный код

#include <iostream>
#include <string>

template<typename T>
class DoubleLinkedList
{
public:
    DoubleLinkedList();
    DoubleLinkedList(const DoubleLinkedList<T>& src);
    DoubleLinkedList(DoubleLinkedList<T>&& other) noexcept;

    T& operator[](const int index);
    bool operator==(const DoubleLinkedList<T>& right);
    friend std::ostream& operator<<(std::ostream os, DoubleLinkedList<T>& list);

    void insertHead(T data);
    void insertTail(T data);
    bool deleteHead();
    bool deleteTail();
    bool deleteItem(const T data);
    bool searchItem(T data);
    bool replaceItem(T itemOld, T itemNew);
    void add(DoubleLinkedList<T>& src);
    void outAll();

    void clear();
    ~DoubleLinkedList();
private:
    template<typename T>
    class Node 
    {
    public:
        Node* pNext_;
        Node* pPrev_;
        T data_;

        Node(T data = T(), Node* pNext = nullptr, Node* pPrev = nullptr) 
        {
            this->data_ = data;
            this->pNext_ = pNext;
            this->pPrev_ = pPrev;
        }
    };

    Node<T>* head_;
    Node<T>* tail_;
    int size_;

    void swap(DoubleLinkedList<T>& other) noexcept;
    Node<T>* head() { return head_; }
    Node<T>* tail() { return tail_; }
    void insertHead(Node<T>* x);
    void insertTail(Node<T>* x);
    void deleteNode(Node<T>* x);
    Node<T>* searchNode(T data);
    Node<T>* replaceNode(Node<T>* x, T data);

};

template<typename T>
DoubleLinkedList<T>::DoubleLinkedList()
{
    head_ = tail_ = nullptr;
    size_ = 0;
}

template<typename T>
DoubleLinkedList<T>::DoubleLinkedList(const DoubleLinkedList<T>& src)
{
    this->clear();
    Node<T>* temp = src.head_;
    for (int i = 0; i < src.size_; i++)
    {
        insertTail(temp->data_);
        temp = temp->pNext_;
    }
}

template<typename T>
DoubleLinkedList<T>::DoubleLinkedList(DoubleLinkedList<T>&& other) noexcept
{
    this->head_ = other.head_;
    this->tail_ = other.tail_;
    this->size_ = other.size_;

    other.head_ = other.tail_ = nullptr;
    other.size_ = 0;
}

template<typename T>
T& DoubleLinkedList<T>::operator[](const int index)
{
    int counter = 0;
    Node<T>* current = head_;
    while (current != nullptr)
    {
        if (counter == index) 
        {
            return current->data_;
        }
        current = current->pNext_;
        counter++;
    }
}

template<typename T>
bool DoubleLinkedList<T>::operator==(const DoubleLinkedList<T>& right)
{
    if (size_ != right.size_) 
    {
        return 0;
    }
    else
    {
        Node<T>* currentLeft = head_;
        Node<T>* currentRight = right.head_;
        while (currentLeft != nullptr) 
        {
            if (currentLeft->data_ != currentRight->data_) 
            {
                return 0;
            }
            else
            {
                currentLeft = currentLeft->pNext_;
                currentRight = currentRight->pNext_;
            }
        }
        return 1;
    }
}

template<typename T>
void DoubleLinkedList<T>::insertHead(T data)
{
    insertHead(new Node<T>(data));
}

template<typename T>
void DoubleLinkedList<T>::insertTail(T data)
{
    insertTail(new Node<T>(data));
}

template<typename T>
bool DoubleLinkedList<T>::deleteHead()
{
    if (head_ == nullptr) 
    {
        return 0;
    }
    Node<T>* toDelete = head_;
    head_ = head_->pNext_;
    delete toDelete;
    size_--;
    return 1;
}

template<typename T>
bool DoubleLinkedList<T>::deleteTail()
{
    if (tail_ == nullptr)
    {
        return 0;
    }
    Node<T>* toDelete = tail_;
    tail_ = tail_->pPrev_;
    delete toDelete;
    size_--;
    return 1;
}

template<typename T>
bool DoubleLinkedList<T>::deleteItem(const T data)
{
    try
    {
        return (deleteNode(searchNode(data)) != nullptr);
    }
    catch (const char* ex)
    {
        std::cout << ex << std::endl;
        return 0;
    }
}

template<typename T>
bool DoubleLinkedList<T>::searchItem(T data)
{
    return (searchNode(data) != nullptr);
}

template<typename T>
bool DoubleLinkedList<T>::replaceItem(T itemOld, T itemNew)
{
    try
    {
        return (replaceNode(searchNode(itemOld), itemNew) != nullptr);
    }
    catch (const char* ex)
    {
        std::cout << ex << std::endl;
        return 0;
    }

}

template<typename T>
void DoubleLinkedList<T>::add(DoubleLinkedList<T>& src)
{
    Node<T>* toAdd;
    while (src.size_)
    {
        toAdd = src.head_;
        src.head_ = src.head_->pNext_;
        insertTail(toAdd);
        src.size_--;
    }
}

template<typename T>
void DoubleLinkedList<T>::outAll()
{
    for (int i = 0; i < size_; i++)
    {
        std::cout << '[' << this[i] << "] ";
    }
    std::cout << std::endl;
}

template<typename T>
void DoubleLinkedList<T>::clear()
{
    while (size_)
    {
        deleteHead();
    }
}

template<typename T>
DoubleLinkedList<T>::~DoubleLinkedList()
{
    clear();
}

template<typename T>
void DoubleLinkedList<T>::swap(DoubleLinkedList<T>& other) noexcept
{
    std::swap(this->head_, other.head_);
    std::swap(this->tail_, other.tail_);
    std::swap(this->size_, other.size_);
}

template<typename T>
void DoubleLinkedList<T>::insertHead(Node<T>* x)
{
    x->pNext_ = head_;
    if (head_ != nullptr) 
    {
        head_->pPrev_ = x;
    }
    else
    {
        tail_ = x;
    }
    head_ = x;
    size_++;
}

template<typename T>
void DoubleLinkedList<T>::insertTail(Node<T>* x)
{
    x->pPrev_ = tail_;
    if (tail_ != nullptr) 
    {
        tail_->pNext_ = x;
    }
    else
    {
        head_ = x;
    }
    tail_ = x;
    size_++;
}

template<typename T>
void DoubleLinkedList<T>::deleteNode(Node<T>* x)
{
    if (x == nullptr) {
        throw ("DoubleLinkedList::deleteNode  - incorrect node address");
    }
    if (x->pPrev_ != nullptr) 
    {
        (x->pPrev_)->pNext_ = x->pNext_;
    }
    else
    {
        head_ = x->pNext_;
    }
    if (x->pPrev_ != nullptr) 
    {
        (x->pNext_)->pPrev_ = x->pPrev_;
    }
    else
    {
        tail_ = x->pPrev_;
    }
    delete x;
    size_--;
}

template<typename T>
DoubleLinkedList<T>::Node<T>* DoubleLinkedList<T>::searchNode(T data)
{
    Node<T>* x = head_;
    while (x != nullptr && x->data_ != data) 
    {
        x = x->pNext_;
    }
    return x;
}

template<typename T>
DoubleLinkedList<T>::Node<T>* DoubleLinkedList<T>::replaceNode(Node<T>* x, T data)
{
    if (x == nullptr) {
        throw ("DoubleLinkedList::replaceNode  - incorrect node address");
    }
    x->data_ = data;
    return x;
}

template<typename T>
std::ostream& operator<<(std::ostream& os, DoubleLinkedList<T>& list) 
{
    for (int i = 0; i < list.size_; i++)
    {
        os<< '[' << list[i] << "] ";
    }
}

int main()
{
    DoubleLinkedList<int> a;
    a.insertHead(40);
    a.insertHead(100);
    a.insertTail(20);

    std::cout << a;

    /*a.outAll();*/
}

Буду благодарен, если объясните, что я делаю не так.

Ответы

▲ 2Принят

Не копаясь во всем коде, уж очень его много, и рассматривая только оператор <<...

Первое — у вас несоответствие объявления реализации, в объявлении ostream os, каковое требует копирования потока, а оно явно запрещено.

Второе... Если вас устраивает дружественность для любого оператора, независимо от используемого аргумента шаблона, то используйте другое имя параметра шаблона —

template<typename U>
friend std::ostream& operator<<(std::ostream& os, DoubleLinkedList<U>& list);

Если надо строгое соответствие дружбы только для своего типа — тут сложнее, но на ruSO этот вопрос точно поднимался, поищите.

Да, и не забудьте в операторе вернуть return os, раз уж пообещали...