Friday, 8 April 2016

c++ - Using a custom class with a custom template container




I'm trying to define a custom template container, and then add custom class objects (Students) into it. Here's my code:



class Student{
public:
string subject;
Student(string _subject){
subject = _subject;
}
};



And here's my LinkedList template code



template 
class LinkedList{

private:
struct Node{
Node *next;
T value;

};
Node *root;
Node *curr;
int count;

public:
LinkedList() : count(0), root(NULL){}
void add(T val){
if (root == NULL){
root = new Node;

root->value = val;
root->next = NULL;
curr = root;
}
else{
curr->next = new Node;
curr = curr->next;
curr->value = val;
curr->next = NULL;
}

count++;
}

void print(){
for (Node *itr=root; itr != NULL; itr = itr->next){
cout << itr->value << endl;
}
}
};


int main(){
LinkedList a;
Student sam("Math");
a.add(sam)
}


When I run it, I get





linkedlist.cpp: In constructor ‘LinkedList::Node::Node()’:
linkedlist.cpp:27: instantiated from ‘void LinkedList::add(T) [with T = Student]’



linkedlist.cpp:133: instantiated from here



linkedlist.cpp:27: error: no matching function for call to ‘Student::Student()’
linkedlist.cpp:18: note: candidates are: Student::Student(std::string)



linkedlist.cpp:15: note: Student::Student(const Student&)
linkedlist.cpp: In member function ‘void LinkedList::add(T) [with T = Student]’:




linkedlist.cpp:40: note: synthesized method ‘LinkedList::Node::Node()’ first required here




I have no clue what that error really means, and what it's asking me to do. If I do this instead:



int main(){
LinkedList a;
Student sam("Math");
a.add(&sam);

}


It works just fine.



But storing references to objects is not what I'm after. How can I get my LinkedList to make copies of the object I wish to add to it?



Thanks in advance!


Answer



First of all...




#include 


Now, change this...



struct Node {
Node* next;
T value;
};



For...



struct Node {
Node* next;
T value;

inline Node(const T &value) : value(value), next(nullptr) {}
inline Node(T &&value) : value(std::move(value)), next(nullptr) {}

};


And, this...



void add(T val) {
if(this->root == nullptr) {
this->root = new Node;
this->root->value = val;
root->next = NULL;

curr = root;
} else {
curr->next = new Node;
curr = curr->next;
curr->value = val;
curr->next = NULL;
}

count++;
}



For this...



void add(const T &val){
if(this->root == nullptr) {
this->root = new Node(val);
this->curr = root;
} else {
this->curr->next = new Node(val);

this->curr = this->curr->next;
}

this->count++;
}

void add(T &&val){
if(this->root == nullptr) {
this->root = new Node(std::move(val));
this->curr = root;

} else {
this->curr->next = new Node(std::move(val));
this->curr = this->curr->next;
}

this->count++;
}


What happens is that you're creating a Node object with new Node with it's implicit default constructor. That implies that the default constructor for Node::value is called. Then, can you tell me if there's any? No. Student does not have a default constructor, so this won't work.




BTW, I made some minor redesigns to your code, so to avoid several issues that appeared by the way. As a bonus, you can now use move semantics (try list.add(Student("Joe")))!



Also, remember to initialize curr to nullptr in the constructor initialization list!


No comments:

Post a Comment

c++ - Does curly brackets matter for empty constructor?

Those brackets declare an empty, inline constructor. In that case, with them, the constructor does exist, it merely does nothing more than t...