简体   繁体   中英

Error in implementing emplace_back() binary '=': no operator found which takes a right-hand operand of type 'T *'

Code below, for my linked list implementation and specifically emplace_back below. What am I doing wrong and how to fix?

Error I am getting is:

Build started...
1>------ Build started: Project: so_list_emplace, Configuration: Debug Win32 ------
1>main.cpp
1list.hpp(191,19): error C2280: 'list<President>::node::node(void)': attempting to reference a deleted function
1>list.hpp(15): message : compiler has generated 'list<President>::node::node' here
1>list.hpp(15,1): message : 'list<President>::node::node(void)': function was implicitly deleted because a data member 'list<President>::node::value' has either no appropriate default constructor or overload resolution was ambiguous
1>list.hpp(12): message : see declaration of 'list<President>::node::value'
1>main.cpp(29): message : see reference to function template instantiation 'void list<President>::emplace_back<const char(&)[15],const char(&)[13],int>(const char (&)[15],const char (&)[13],int &&)' being compiled
1>main.cpp(29): message : see reference to function template instantiation 'void list<President>::emplace_back<const char(&)[15],const char(&)[13],int>(const char (&)[15],const char (&)[13],int &&)' being compiled
1>list.hpp(192,10): error C2679: binary '=': no operator found which takes a right-hand operand of type 'T *' (or there is no acceptable conversion)
1>        with
1>        [
1>            T=President
1>        ]
1>main.cpp(22,13): message : could be 'President &President::operator =(const President &)'
1>list.hpp(190,1): message : while trying to match the argument list '(T, T *)'
1>        with
1>        [
1>            T=President
1>        ]
1>Done building project "so_list_emplace.vcxproj" -- FAILED.

list.hpp implementation:

#ifndef LIST_HPP_
#define LIST_HPP_

#include <cstddef>
#include <initializer_list>
#include <utility>

template< typename T >
class list {
public:
    struct node {
        T value;
        node* next;
        node* prior;
    };

    struct iterator {

        iterator(node* nod) : ptr_(nod) {}

        iterator& operator++() {
            if (ptr_) {
                ptr_ = ptr_->next;
            }
            return *this;
        }

        iterator operator++(T) {
            auto old = *this;
            if (ptr_) {
                ptr_ = ptr_->next;
            }
            return old;
        }

        T& operator*() const { return ptr_->value; }
        T* operator->() { return &ptr_->value;  }

        bool operator==(const iterator& other) { return ptr_ == other.ptr_;  }
        bool operator!=(const iterator& other) { return ptr_ != other.ptr_; }

        node* ptr_;
    };


    list() : head_(nullptr), tail_(nullptr), size_(0) {}

    // O(n)
    template< typename input_iterator >
    list(input_iterator first, input_iterator last) : head_(nullptr), tail_(nullptr), size_(0) {

        for (auto it = first; it != last; ++it) {
            push_back(*it);
        }
    }

    // O(n)
    list(std::initializer_list<T> init) : list<T>(init.begin(), init.end()) {}

    // O(n)
    list(const list& other) : head_(nullptr), tail_(nullptr), size_(0) {
        auto it = other.begin();
        while (it != nullptr) {
            push_back(*it);
            ++it;
        }
        size_ = other.size();
    }

    // O(n)
    list& operator=(const list& other) {
        if (this != &other) {
            clear();
            auto it = other.begin();
            while (it != nullptr) {
                push_back(*it);
                ++it;
            }
            size_ = other.size();
        }
        return *this;
    }

    list(list&& other) : head_(other.head_), tail_(other.tail_), size_(other.size()) {
        other.size_ = 0;
        other.head_ = nullptr;
        other.tail_ = nullptr;
    }

    list& operator=(list&& other) {
        head_ = other.head_;
        tail_ = other.tail_;
        size_ = other.size();

        other.clear();
        other.head_ = nullptr;
        other.tail_ = nullptr;
        other.size_ = 0;
    }

    // O(n)
    ~list() {
        clear();
    }

    // O(n)
    void clear() {
        if (head_) {
            node* current = head_;
            while (current) {
                node* next = current->next;
                delete current;
                current = next;
            }
        }
        head_ = nullptr;
        tail_ = nullptr;
        size_ = 0;
    }

    // O(1)
    bool empty() const {
        return head_ == nullptr;
    }

    // O(1)
    void push_back(const T& value) {

        node* newnode = make_node(value);

        if (tail_) {
            node* oldtail = tail_;
            oldtail->next = newnode;
            newnode->prior = oldtail;
            tail_ = newnode;
        }
        else {
            head_ = tail_ = newnode;
        }
        ++size_;
    }

    // O(1)
    size_t size() const {
        return size_;
    }

    iterator begin() {
        return iterator(head_);
    }
    const iterator begin() const {
        return iterator(head_);
    }

    iterator end() {
        return nullptr;
    }
    const iterator end() const {
        return nullptr;
    }

    // O(1)
    T& front() { return *iterator(head_); }
    const T& front() const { return *iterator(head_); }

    // O(1)
    T& back() { return *iterator(tail_); }
    const T& back() const { return *iterator(tail_); }

    // O(1)
    void pop_back() {
        if (tail_) {
            node* newtail = tail_->prior;
            if (newtail) {
                newtail->next = nullptr;
            }
            else {
                // means that head_ has also been erased
                head_ = nullptr;
            }

            delete tail_;
            tail_ = newtail;
            --size_;
        }
    }

    template<typename... P>
    void emplace_back(P&&... v)
    {
        node* newnode = new node;
        newnode->value = new T(std::forward<P>(v)...);
        newnode->next = nullptr;
        newnode->prior = nullptr;

        if (tail_) {
            node* oldtail = tail_;
            oldtail->next = newnode;
            newnode->prior = oldtail;
            tail_ = newnode;
        }
        else {
            head_ = tail_ = newnode;
        }
        ++size_;
    }

private:
    node* make_node(const T& value) {
        node* newnode = new node;
        newnode->value = value;
        newnode->next = nullptr;
        newnode->prior = nullptr;
        return newnode;
    }

    node* head_;
    node* tail_;
    size_t size_;
};

#endif // LIST_HPP_

main.cpp to exercise:

#include "list.hpp"

#include <iostream>
#include <string>

struct President
{
    std::string name;
    std::string country;
    int year;

    President(std::string p_name, std::string p_country, int p_year)
        : name(std::move(p_name)), country(std::move(p_country)), year(p_year)
    {
        std::cout << "I am being constructed.\n";
    }
    President(President&& other)
        : name(std::move(other.name)), country(std::move(other.country)), year(other.year)
    {
        std::cout << "I am being moved.\n";
    }
    President& operator=(const President& other) = default;
};

int main() {

    list<President> elections;

    elections.emplace_back("Nelson Mandela", "South Africa", 1994);
}

Your issue is that node is trying to construct a President , but President doesn't have a default constructor. You'll need to construct a node with a President , like in this constructor:

node(T const &v) : value(v) { }

Because emplace_back tries to construct an object in place, you'll also need to add a constructor to construct value using the arguments that are passed in.

template <typename ...Args>
node(Args &&...v) : value(std::forward<Args>(v)...) { }

Lastly, update your emplace_back function to forward arguments at construction time.

node* newnode = new node(std::forward<P>(v)...);

This is compiling for me with gcc and clang.

The problems(as reflected in the errors) are:

  1. There is no default constructor for list::node::node() because it is implicitly deleted .

  2. President has no default constructor because you've user defined constructors for President and so compiler will not synthesize the default constructor for you.

  3. There is no operator= for President .

To solve these problems you need to add the following things:

  1. Default constructor for node like node() = default(); inside node .
  2. Default constructor for President like President() = default; inside President .
  3. Define(overload) the assignment operator for President .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM