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:
There is no default constructor for
list::node::node()
because it is implicitly deleted.President
has no default constructor because you've user defined constructors forPresident
and so compiler will not synthesize the default constructor for you.There is no
operator=
forPresident
.
To solve these problems you need to add the following things:
- Default constructor for
node
likenode() = default();
insidenode
. - Default constructor for
President
likePresident() = default;
insidePresident
. - Define(overload) the assignment operator for
President
.