Home > front end >  Error in implementing emplace_back() binary '=': no operator found which takes a right-han
Error in implementing emplace_back() binary '=': no operator found which takes a right-han

Time:04-03

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);
}

CodePudding user response:

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.

CodePudding user response:

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.
  • Related