I am attempting to code an assignment operator for a linked list class in c++. The errors I'm getting say that "head" is undeclared, but I'm not sure where I'm supposed to declare it. It's being used in other functions without a problem. Another error says my use of "this" is invalid.
template <class T>
SortedLinkList<T>& operator=(const SortedLinkList<T> & otherList)
{
if(&otherList != this) {
Node<T> temp = head;
while(temp->getNext() != NULL) {
head = head -> getNext();
delete temp;
temp = head;
}
count = 0;
temp = otherList.head;
while(temp != NULL) {
insert(temp);
}
}
return *this;
}
The this pointer is unavailable because your function signature does not resemble a member definition, you're missing the type scope resolution part of the signature:
template <class T>
SortedLinkList<T>& operator=(const SortedLinkList<T> & otherList)
should be:
template <class T>
SortedLinkList<T>& SortedLinkList<T>::operator=(const SortedLinkList<T> & otherList)
Related
I don't understand what is wrong when I overload operator +
(purpose of this is to join 2 stacks in one new) ...
it returns "sum" of but change values for those previous.
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
template <typename T>
classStack
{
private:
struct Node
{
T data;
Node *next;
} *top;
std::size_t size;
public:
Stack();
~Stack();
void push(T data);
void pop(void);
size_t get_size(void);
const Stack& operator=(const Stack &stack_obj);
const Stack operator+(const Stack &stack_obj);
void show_all_stack(void);
};
template <typename T>
const Stack<T> Stack<T>::operator+(const Stack &stack_obj)
{
Stack stack;
Node *tmp;
if (!this->size && !stack_obj.size) {
return stack;
}
if (!stack_obj.size)
{
stack.size = size;
stack.top = top;
}
else if (!size)
{
stack.size = stack_obj.size;
stack.top = stack_obj.top;
}
else
{
stack.size = size + stack_obj.size;
stack.top = new Node;
stack.top = top;
tmp = stack.top;
while (tmp->next)
tmp = tmp->next;
tmp->next = new Node;
tmp->next = stack_obj.top;
}
return stack;
}
Default constructor
template <typename T>
Stack<T>::Stack(void): top(nullptr), size(0)
{
}
Destructor
template <typename T>
Stack<T>::~Stack(void)
{
Node *next;
if (!size)
std::cout << "Stack is empty!\n";
else
{
while (top != nullptr)
{
next = top->next;
delete top;
top = next;
}
top = nullptr;
}
}
Assignment operator
template <typename T>
const Stack<T>& Stack<T>::operator=(const Stack<T> &stack_obj)
{
Node *tmp;
Node *ptr;
Node *last;
Node *new_node;
if (&stack_obj != this)
{
while (top != nullptr)
{
tmp = top;
top = top->next;
delete tmp;
}
top = nullptr;
size = stack_obj.size;
ptr = stack_obj.top;
while (ptr)
{
new_node = new Node;
new_node->data = ptr->data;
new_node->next = nullptr;
if (!top)
{
top = new_node;
last = new_node;
}
else
{
last->next = new_node;
last = new_node;
}
ptr = ptr->next;
}
}
}
Before creating functions that return Stack<T> by value, or have functions that require copy semantics for Stack<T> (as in your operator +), you need to make sure that Stack<T> is safely copyable. Right now, you are lacking a copy constructor, thus your operator + would never work correctly, even if the function itself is bug-free.
You're missing this function:
Stack::Stack(const Stack<T>&)
The easiest way to implement the copy constructor is to take most of your code out of the assignment operator, and place that into the copy constructor. More or less, the code should look something like this (the code has not been compiled or tested -- it is there to illustrate the main point of this answer):
template <typename T>
Stack<T>::Stack<T>(const Stack<T> &stack_obj) : top(nullptr), size(0)
{
Node *tmp;
Node *ptr;
Node *last;
Node *new_node;
ptr = stack_obj.top;
while (ptr)
{
new_node = new Node;
new_node->data = ptr->data;
new_node->next = nullptr;
if (!top)
{
top = new_node;
last = new_node;
}
else
{
last->next = new_node;
last = new_node;
}
ptr = ptr->next;
}
}
You have already written a destructor that should work, so we won't get into that function, but a working destructor is required for the next step -- implementation of the assignment operator.
Now that you have a copy constructor and destructor, you can now write the assignment operator. The technique used here is the copy / swap idiom
#include <algorithm>
//...
template <typename T>
Stack<T>& Stack<T>::operator=(const Stack<T> &stack_obj)
{
if ( &stack_obj != this )
{
Stack<T> temp(stack_obj);
std::swap(top, temp.top);
std::swap(size, temp.size);
}
return *this;
}
Believe it or not, this works. The code that used to be here was moved to the copy constructor, and thus the assignment operator is going to take advantage of the copy constructor.
To explain briefly, the code creates a temporary Stack<T> object from the passed-in stack_obj (this is why you need a working copy constructor). Then all that is done is to swap out the this members with the temporary members. Last, the temp dies off with the old data (this is why the destructor needs to be working correctly).
Note that you need to swap all of the members, so if you add more members to the Stack<T> class, you need to swap them in the assignment operator.
Once you have the basic 3 functions (copy, assign, destroy) written correctly, then and only then should you write functions that return Stack<T> by value, or write functions that take a Stack<T> by value.
You may have other issues with operator + that lie outside the scope of what this answer is presenting to you, but the gist of it is that your class requires that it has correct copy semantics before implementing +.
I'm learning about linked list. I created a template implementation, with a constructor, an inserter, a destructor, a copy constructor and an overloaded assignment operator. The problem is that my test programme doesn't output anything after overloading assignment operator.
For my assignment operator, I use a Clear() function to clear the list entirely before the copy. I put it in the destructor and checked that it works fine. I also checked my copy constructor and it worked fine as well.
File node.h: defines the node building block
#include <iostream>
using namespace std;
template <typename T>
struct Node{
T _item;
Node<T>* _next;
Node() {
_item = T();
_next = NULL;
}
Node(T item){
_item = item;
_next = NULL;
}
// Print the value of a node
friend std::ostream& operator <<(std::ostream& outs, const Node<T> &printMe){
outs << "[" << printMe._item << "]";
return outs;
}
};
File list.h: defines the linked list template
#include "node.h"
template <class T>
class List {
public:
// default constructor
List();
// Destructor
~List();
// Copy constructor
List(const List<T> ©This);
// Overloading assignment operator
List& operator =(const List& RHS);
// Insert i to the head of the linked list
Node<T>* InsertHead(T i);
// Clear a linked list
void Clear();
// Overload the output operator to print the list
template <class U>
friend ostream& operator <<(ostream& outs, const List<U>& l);
private:
Node<T>* head;
};
This header also provides the implementation of these member functions:
template <class T>
List<T>::List(){
head = NULL;
}
template <class T>
List<T>::~List(){
Clear();
}
template <class T>
List<T>::List(const List<T> ©This){
if (copyThis.head == NULL)
head = NULL;
else {
// Create walker for the original linked list
Node<T>* walker = copyThis.head->_next;
// Create new head node for new linked list
head = new Node<T>(copyThis.head->_item);
// Create new walker for new linked list
Node<T>* new_walker = head;
// Iterate walker and new walker and copy each item in the original list to new linked list
while (walker!= NULL) {
new_walker->_next = new Node<T>(walker->_item);
walker = walker->_next;
new_walker = new_walker->_next;
}
}
}
template <class T>
List<T>& List<T>::operator =(const List<T>& RHS){ // DOESN'T WORK
if (this != &RHS) {
this->Clear();
*this = List<T>(RHS);
}
return *this;
}
template <class T>
Node<T>* List<T>::InsertHead(T i){
Node<T>* temp = new Node<T>(i);
temp->_next = head;
head = temp;
return head;
}
// Clear a linked list
template <class T>
void List<T>::Clear(){
Node<T>* current = head;
Node<T>* next = new Node<T>;
while (current != NULL) {
next = current->_next;
delete current;
current = next;
}
head = NULL;
}
template <class U>
ostream& operator <<(ostream& outs, const List<U>& l){
Node<U>* walker = l.head;
while(walker != NULL){
outs << *walker;
outs << "->";
walker = walker->_next;
}
outs << "|||";
return outs;
}
File main.cpp: tests the classes
#include <iostream>
#include "list.h"
using namespace std;
int main() {
List<int> a;
a.InsertHead(17);
a.InsertHead(35);
a.InsertHead(6);
a.InsertHead(54);
a.InsertHead(6);
cout << a <<endl;;
List<int> b;
b.InsertHead(3);
b.InsertHead(2);
cout << b <<endl;;
a = b;
cout << a <<endl; // PROBLEM: NOTHING IS DISPLAYED
cout << b <<endl;
}
The problem I currently have is the overloading assignment operator function. Below is when I copy the whole execution from the copy constructor function and it runs.
template <class T>
List<T>& List<T>::operator =(const List<T>& RHS){
if (this != &RHS) {
this->Clear();
if (copyThis.head == NULL)
head = NULL;
else {
// Create walker for the original linked list
Node<T>* walker = copyThis.head->_next;
// Create new head node for new linked list
head = new Node<T>(copyThis.head->_item);
// Create new walker for new linked list
Node<T>* new_walker = head;
// Iterate walker and new walker and copy each item in the original list to new linked list
while (walker!= NULL) {
new_walker->_next = new Node<T>(walker->_item);
walker = walker->_next;
new_walker = new_walker->_next;
}
}
return *this;
}
The output for this is:
2->3->|||
However, when I simplify the code like below, it doesn't output anything:
template <class T>
List<T>& List<T>::operator =(const List<T>& RHS){
if (this != &RHS) {
this->Clear();
*this = List<T>(RHS);
}
return *this;
}
Can anyone tell me why it doesn't work and how to simplify it efficiently? I really appreciate it.
The problem
The assignment operator stops everything because of a stack overflow.
In fact, your implementation of the assignment operator uses itself the assignment operator, so that it calls itself recursively until the stack is exhausted:
*this = List<T>(RHS); // OUCH !!
| | |
V V V
<ListT> operator= List<T> ==> cals operator= again !!
The solution
Rewrite the operator so that it doesn't call itself.
Possibly clone every node, so to avoid that 2 lists share the same node and tha the first one that frees its node causes dangling pointers and UB for the other.
Not related, but please avoid using namespaces in headers. This is an extremely bad habit for later.
Additional tip: This article recommends some good and elegant practices for operator overloading. For the assignment operator, it suggests to use the copy constructor (as you attempt to do) but instead of assigning (your problem), swapping (to be verified, but swapping the heads in your case would certainly do the trick).
I'm new to C++ and have been trying to implement a Singly Linked List, that provides an implementation the destructor, copy constructor and assignment operator. I'm running into compilation issues when trying to implement the copy constructor and the assignment operator.
Here's node.hpp
#ifndef LINKED_LIST_NODE_HPP
#define LINKED_LIST_NODE_HPP
template <typename T>
class Node{
public:
T data;
Node* next;
Node();
Node(T);
Node(const Node&);
~Node();
};
template <typename T>
Node<T>::Node(){}
template <typename T>
Node<T>:: Node(const T data): data(data), next(nullptr){}
template <typename T>
Node<T>::Node(const Node<T>& source) : data(source.data),
next(new Node)
{
(*next) = *(source.next) ;
}
template <typename T>
Node<T>::~Node(){}
#endif //LINKED_LIST_NODE_HPP
This is singly_linked_list.hpp
#ifndef LINKED_LIST_SINGLYLINKEDLIST_HPP
#define LINKED_LIST_SINGLYLINKEDLIST_HPP
#include <iostream>
#include "node.hpp"
template <typename T>
class SinglyLinkedList {
private:
Node<T>* head;
std::size_t count;
public:
SinglyLinkedList();
SinglyLinkedList(const SinglyLinkedList& source);
SinglyLinkedList& operator=(const SinglyLinkedList& source);
~SinglyLinkedList();
void insert(T);
void remove(T);
bool isEmpty();
int length();
void print();
};
template <typename T>
SinglyLinkedList<T>::SinglyLinkedList() : head(nullptr), count(0){}
template <typename T>
template <typename T>
SinglyLinkedList<T>::SinglyLinkedList(const SinglyLinkedList& source){
Node<T>* curr = source.head;
while(curr != nullptr){
Node<T>* p = new Node<T>;
p->data = curr->data;
curr = curr->next;
}
}
//template <typename T>
//SinglyLinkedList<T>::SinglyLinkedList& operator=(const SinglyLinkedList<T>& source){
// //not sure how to implment this.
//}
template <typename T>
SinglyLinkedList<T>::~SinglyLinkedList() {
if(!isEmpty()){
Node<T>* temp = head;
Node<T>* prev = nullptr;
while(temp->next != nullptr){
prev = temp;
temp = temp->next;
delete prev;
}
delete temp;
}
}
template <typename T>
bool SinglyLinkedList<T>::isEmpty() {
return head == nullptr;
}
template <typename T>
void SinglyLinkedList<T>::insert(T item) {
Node<T>* p = new Node<T>(item);
p->next = head;
head = p;
count += 1;
}
template <typename T>
void SinglyLinkedList<T>::remove(T item) {
bool present = false;
if (head->data == item){
Node<T>* temp = head;
head = head->next;
delete(temp);
count -= 1;
return;
}
Node<T>* temp = head;
while (temp->next != nullptr){
if (temp->next->data == item){
Node<T>* removable = temp->next;
temp->next = temp->next->next;
delete(removable);
present = true;
count -= 1;
break;
} else{
temp = temp->next;
}
}
if(!present){
throw std::invalid_argument("item not present in list");
}
}
template <typename T>
int SinglyLinkedList<T>::length() {
return count;
}
template <typename T>
void SinglyLinkedList<T>::print() {
if(isEmpty()){
throw std::invalid_argument("Can't print an empty list!");
}
Node<T>* temp = head;
while(temp != nullptr){
if(temp->next != nullptr){
std::cout<<temp->data;
std::cout<<"->";
}else{
std::cout<<temp->data;
}
temp = temp->next;
}
std::cout<<std::endl;
}
#endif //LINKED_LIST_SINGLYLINKEDLIST_HPP
I've commented out the copy constructor code to make this compile. What is the correct way of doing this? I'm just learning C++.
One issue that introduces complexity is that it is not well defined what the copy constructor of a node should do? Should the next field of the copy point to the next of the original, or it should create a copy of the next and point to that? The former is inadequate and error-prone, the latter would recursively create a copy of the whole list, one node at a time. This will work for lists of small size but will cause stack overflow for lists with many elements due to the depth of the recursive calls.
So to keep things simple, I wouldn't bother with copy constructor of a node.
template <typename T>
class Node {
public:
T data;
Node* next = nullptr;
Node() = default;
Node(const Node&) = delete; // since copying is not well defined, make it impossible to copy a node.
};
Copying a list is a well defined operation, so implementing the copy constructor makes sense. A mistake with your current implementation is that you allocate a new node, only to leak it later (nothing keeps track of the newly allocated node p). What you need looks more like this:
template <typename T>
SinglyLinkedList<T>::SinglyLinkedList(const SinglyLinkedList<T>& source)
: head(nullptr)
, count(0)
{
// deal with the trivial case of empty list
if (source.head == nullptr)
return;
// deal with the case where count >= 1
head = new Node<T>;
head->data = source.head->data;
head->next = nullptr;
count = 1;
Node<T>* lastCopied = source.head; // last node to be copied
Node<T>* lastAdded = head; // last node to be added to the current list
while (lastCopied->next != nullptr)
{
// create new node
Node<T>* p = new Node<T>;
p->data = lastCopied->next->data;
p->next = nullptr;
// link the newly created node to the last of the current list
lastAdded->next = p;
lastAdded = p;
// advance lastCopied
lastCopied = lastCopied->next;
count++;
}
}
Now regarding the assignment operator, luckily you can use the 'copy and swap' idiom that greatly simplifies things.
template <typename T>
SinglyLinkedList<T>& SinglyLinkedList<T>::operator =(SinglyLinkedList<T> source) // note that you pass by value.
{
std::swap(head, source.head);
std::swap(count, source.count);
return *this;
}
My answer would become too long if I tried to explain the copy and swap technique. It is a clever trick to write exception safe code and avoid duplication (implements assignment by using the copy ctor) at the same time. It is worth reading about it here.
Btw, the declaration of your class should look like this
template <typename T>
class SinglyLinkedList
{
private:
Node<T>* head = nullptr;
std::size_t count = 0;
public:
SinglyLinkedList(const SinglyLinkedList& source);
SinglyLinkedList& operator=(SinglyLinkedList source);
// other members here...
};
PS. My code assumes you are using c++11 or a later standard.
I don't like the direction this is headed. I'm going to explain how to do this approach right because it is an excellent lesson on recursion, but because it's recursion it can run the program out of Automatic storage (march off the end of the stack, most likely) with a sufficiently large list. Not cool.
The logic:
Copying a node copies the next node if there is one. This looks something like
template <typename T>
Node<T>::Node(const Node<T>& source) : data(source.data)
{
if (source.next) // if there is a next, clone it
{
next = new Node<T>(*source.next);
}
else
{
next = nullptr;
}
}
This reduces the linked list copy constructor to
template <typename T>
SinglyLinkedList<T>::SinglyLinkedList(const SinglyLinkedList& source){
head = new Node<T>(*source.head); //clone the head. Cloning the head will clone everything after
count = source.count;
}
A helper function may, uh... help here to make the Node copy constructor a bit more idiomatic
template <typename T>
Node<T> * initnext(const Node<T> & source)
{
if (source.next)
{
return new Node<T>(*source.next);
}
else
{
return nullptr;
}
}
template <typename T>
Node<T>::Node(const Node<T>& source) : data(source.data),
next(initnext(source))
{
}
but I don't think you gain much.
So... I don't like the above. What would I do instead? Something a lot like opetroch's solution above, but different enough that I'll write this up.
The node stays brutally stupid. As far as I'm concerned all a Node should ever know is how to store the payload and find other Nodes. This means the linked list should do all of the heavy lifting.
Concept 1: head is nothing but a next pointer. Once you abstract away its differences, unimportant here, you can use it exactly the same way you would next.
Concept 2: If you only know where next points, you have to do a bunch of extra book-keeping to track the previous node to update it's next. But if you take advantage of the previous's next pointing to the current node, you can throw out even more code. By tracking the previous node's next you have all of the information you need.
Concept 3: If you keep a pointer to the previous node's next, you can update that previous node's next any time you want by dereferencing it.
template <typename T>
SinglyLinkedList<T>::SinglyLinkedList(const SinglyLinkedList& obj)
{
Node<T>* tocopy = obj.head;
Node<T>** nextpp = &head; // head is a next. We are now pointing to a pointer to next
while (tocopy) // keep looping until there is no next node to copy
{
*nextpp = new Node<T>(tocopy->data); // copy source and update destination's next
nextpp = &(*nextpp)->next; // advance to point at the next of the node we just added
tocopy= tocopy->next; // get next node to copy
}
count = obj.count;
}
Because this iterates rather than recurses it doesn't eat up Automatic storage (probably the stack) and can keep going until the cows come home.
This logic can also be applied to remove
template <typename T>
void SinglyLinkedList<T>::remove(T item) {
Node<T>** temp = &head; //head is nothing but a next pointer.
// by pointing to where the next is, we don't
// need to track a previous or have special handling
// for the head node
while (*temp){ // because we now have a pointer to a pointer, we need an
// extra dereference
if ((*temp)->data == item){
Node<T>* removable = *temp;
*temp = (*temp)->next;
delete(removable);
count -= 1;
return; // no need for any special magic. Just get out.
} else{
temp = &(*temp)->next; // update the pointer to the next
}
}
// if we got here the node was not found.
throw std::invalid_argument("item not present in list");
}
And following through on head is just a next, we can also gut the destructor:
template <typename T>
SinglyLinkedList<T>::~SinglyLinkedList() {
while(head){ // if head null, list empty
Node<T>* temp = head; // cache so we can delete
head = head->next; // move head
delete temp; //delete removed node
}
}
So I'm trying to overload the ^ operator to perform the intersection between my two sets, but I keep getting this compile time error "Invalid operands to binary expression.
intersection = list ^ listTwo; is what causes the error
My methods work fine without overloading.
Here is my header file.
#ifndef SetHeader_h
#define SetHeader_h
template<typename T>
class Node{
public:
T data;
Node<T> *next;
};
template<typename T>
class SetADT{
private:
Node<T> *head;
public:
SetADT();
~SetADT();
void add(T data);
void print();
bool isDuplicate(T data) const;
SetADT<T> operator ^ (SetADT<T> node);
};
#endif /* SetHeader_h */
Here is my cpp file
#include <iostream>
#include "SetHeader.h"
using namespace std;
template <typename T>
SetADT<T> ::SetADT(){
head = NULL;
}
template<typename T>
SetADT<T> :: ~SetADT<T>(){
cout<<"Set deleted!" << endl;
}
template<typename T>
bool SetADT<T>::isDuplicate(T data) const{
Node<T> *cur = this->head;
while (cur) {
if (cur->data == data) {
return true;
}
cur=cur->next;
}
return false;
}
template <typename T>
void SetADT<T>:: add(T data){
Node<T> *node = new Node<T>();
bool isPresent = isDuplicate(data);
if (!isPresent) {
node->data = data;
node->next = this->head;
this->head = node;
}
}
template <typename T>
void SetADT<T>:: print(){
Node<T> *head = this->head;
if (head == NULL) {
cout << "{}";
}
Node<T> *cur = head;
while (cur) {
cout << cur->data << ' ';
cur = cur->next;
}
cout << endl;
}
template <typename T>
SetADT<T> SetADT<T> :: operator &(SetADT<T> one){
SetADT<T> result;
Node<T> *setACurrent = this->head;
while (setACurrent) {
if (one.isDuplicate(setACurrent->data)) {
result.add(setACurrent->data);
}
setACurrent = setACurrent->next;
}
return result;
}
int main (){
SetADT<int> list;
list.add(10);
list.print();
SetADT<int> listTwo;
listTwo.add(10);
list.print();
SetADT<int> intersection;
//error right here
intersection = list ^ listTwo;
return 0;
}
The essence of your problem is that the operator function is defined for the class SetADT<T>, however you are are trying to invoke the ^ operator against pointers (to objects); the compiler does not match your operator function implementation to your usage. Only the bitwise-xor (^) operator is defined and it does not know how to handle SetADT<T> arguments.
In order for the complier to match the invocation with your declaration, you need to dereference the left-hand "argument," list.
intersection = *list ^ listTwo;
I might suggest that you write the operator to accept reference arguments rather than pointers, like so:
SetADT<T>* operator ^ (SetADT<T> &node) { … }
Then you invoke it,
intersection = *list ^ *listTwo;
Of course you can leave the existing declaration/definition in place if there is a reason for it, but it is not nice. You should consider returning a reference to the object rather than a pointer. And, for completeness, you should consider implementing the ^= operator, as well.
SetADT<T>& operator ^ (SetADT<T> &node);
SetADT<T>& operator ^=(const X& rhs);
Then the expression to use for ^ operator could look like,
*intersection = *list ^ *listTwo;
list ^ listTwo;
Both list and listTwo are a SetADT<int> *, a pointer to an instance of this template. Both operands of this ^ operator are pointers.
template<typename T>
class SetADT{
// ...
SetADT<T>* operator ^ (SetADT<T> *node);
Here you defined the ^ operator of a SetADT<T>, and not a SetADT<T> *.
This operator^ declaration ends up overloading an operator on an instance of the class, and not on a pointer to the instance of the class.
That's how operator members work: they overload an operator on an instance of the class, and not on a pointer to an instance of the class.
If you would like to invoke this operator correctly, the right syntax would be:
(*list) ^ listTwo
Here, *list dereferences a pointer to an instance of a class, so you end up with (a reference to) an instance of the class, which has an operator^ overload that takes a pointer to an instance of the same class as a parameter.
Note that your operator overload's parameter is a pointer to an instance of the class, and since listTwo is such a pointer, this should work.
The general mistake you are making is that you are not correctly understanding the fundamental difference between a class and a pointer to an instance of the class. The is not a trivial matter, it's an important distinction. If something is defined to work for an instance of a class, it expects to have an instance of a class to work with, and not a pointer of such a class. And vice-versa.
I have the following main.cpp file
#include "listtemplate.h"
//#include <iostream>
using namespace std;
int main()
{
int UserChoice;
cout << "Hello, World!" << endl;
cin >> UserChoice;
cout << UserChoice;
}
In it's current form, everything works. I enter an integer, and that integer is printed to the screen. However, when I uncomment the cout << "Hello, World!" << endl line, I get the following error
main.cpp:10: error: ambiguous overload for ‘operator<<’ in ‘std::cout << "Hello, World!"’
I can also make it work by commenting out #include "listtemplate.h", uncommenting the hello world line, and including <iostream> in main (currently accessible through the template. Can anyone see what I'm missing here?
listtemplate.h
#ifndef LISTTEMPLATE_H
#define LISTTEMPLATE_H
#include "list.h"
using namespace std;
// Default constructor
template <class Type>
list<Type> :: list() : Head(NULL) {}
// Destructor
template <class Type>
list<Type> :: ~list()
{
Node *Temp;
while (Head != NULL)
{
Temp = Head;
Head = Head -> Next;
delete Temp;
}
}
// Copy constructor
template <class Type>
list<Type> :: list (const Type& OriginalList)
{
Node *Marker;
Node *OriginalMarker;
OriginalMarker = OriginalList.Gead;
if (OriginalMarker == NULL) Head = NULL;
else
{
Head = new Node (OriginalMarker -> Element, NULL);
Marker = Head;
OriginalMarker = OriginalMarker -> Next;
while (OriginalMarker != NULL)
{
Marker -> Next = new Node (OriginalMarker -> Next);
OriginalMarker = OriginalMarker -> Next;
Marker = Marker -> Next;
}
}
}
// Copy assignment operator
template <class Type>
list<Type>& list<Type> :: operator= (const list<Type>& Original)
{
Node *Marker;
Node *OriginalMarker;
// Check that we are not assigning a variable to itself
if (this != &Original)
{
// First clear the current list, if any
while (Head != NULL)
{
Marker = Head;
Head = Head -> Next;
delete Marker;
}
// Now build a new copy
OriginalMarker = Original.Head;
if (OriginalMarker == NULL) Head = NULL;
else
{
Head = new Node (OriginalMarker -> Element, NULL);
Marker = Head;
OriginalMarker = OriginalMarker -> Next;
while (OriginalMarker != NULL)
{
Marker -> Next = new Node (OriginalMarker -> Element, NULL);
OriginalMarker = OriginalMarker -> Next;
Marker = Marker -> Next;
}
}
}
return (*this);
}
// Test for emptiness
template <class Type>
bool list<Type> :: Empty() const
{
return (Head == NULL) ? true : false;
}
// Insert new element at beginning
template <class Type>
bool list<Type> :: Insert (const Type& NewElement)
{
Node *NewNode;
NewNode = new Node;
NewNode -> Element = NewElement;
NewNode -> Next = Head;
return true;
}
// Delete an element
template <class Type>
bool list<Type> :: Delete (const Type& DelElement)
{
Node *Temp;
Node *Previous;
// If list is empty
if (Empty()) return false;
// If element to delete is the first one
else if (Head -> Element == DelElement)
{
Temp = Head;
Head = Head -> Next;
delete Temp;
return true;
}
// If the list has only one element which isn't the specified element
else if (Head -> Next == NULL) return false;
// Else, search the list element by element to find the specified element
else
{
Previous = Head;
Temp = Head -> Next;
while ((Temp -> Element != DelElement) && (Temp -> NExt != NULL))
{
Previous = Temp;
Temp = Temp -> Next;
}
if (Temp -> Element == DelElement)
{
Previous -> Next = Temp -> Next;
delete Temp;
return true;
}
else return false;
}
}
// Print the contents of the list
template <class Type>
void list<Type> :: Print (ostream& OutStream) const
{
Node *Temp;
Temp = Head;
while (Temp != NULL)
{
OutStream << Temp -> Element << " ";
Temp = Temp -> Next;
}
}
// Overloaded output operator
template <class Type>
ostream& operator<< (ostream& OutStream, const list<Type>& OutList)
{
OutList.Print (OutStream);
return OutStream;
}
#endif
list.h
#ifndef LIST_H
#define LIST_H
#include <iostream>
#include <cstddef>
using namespace std;
template <class Type>
class list
{
private:
struct Node
{
public:
Type Element;
Node *Next;
Node() : Next(NULL) {} // Default constructor
Node (Type Data, Node *PNode = NULL) : // Non-default constructor
Element (Data),
Next (PNode) {}
};
Node *Head;
public:
list();
~list();
list (const Type& OriginalList);
bool Empty() const;
bool Insert (const Type& NewElement);
bool Delete (const Type& DelElement);
void Print (ostream& OutStream) const;
list& operator= (const list<Type>& Original);
};
template <class Type>
ostream& operator<< (ostream& OutStream, const Type& OutList);
#endif
This is in fact an interesting question. The main issue is, as others have pointed before that you have declared the following signature:
template <typename T>
std::ostream& operator<<( std::ostream&, T const & );
And that triggers the ambiguity, as it is a catch-all template. But why is it that the compiler can insert (unambiguously) an integer into cout but it cannot insert a const char*?
The reason for that is in the definition of the std::basic_ostream template and free functions that are required in the standard. In particular, the template class basic_ostream contains member functions to insert basic types, including int. On the other hand, the insertion of const char* into streams is defined as a templated free function. Bringing the three declarations together:
namespace std {
template <typename CharT, typename traits = char_traits<CharT> >
class basic_ostream {
// ...
basic_ostream<CharT,traits>& operator<<(int n); // [1]
// ...
};
template<class charT, class traits> // [2]
basic_ostream<charT,traits>& operator<<(basic_ostream<charT,traits>&, const char*);
}
template <typename T> // [3]
std::ostream& operator<<( std::ostream&, T const & ); // user defined
Now, when the compiler encounters the expression std::cout << 5, it finds that [1] is a non-templated perfect match. It is non-templated as std::cout is an object of a concrete instantiation of the basic_ostream class template, when the compiler considers the members of that class, the type is fixed. The method itself is not templated.
The template [3] could match the same use, but because [1] is not templated it takes precedence in the overload resolution, and there is no ambiguity.
Now, when the compiler sees the expression std::cout << "Hello world";, it performs the lookup and it finds (among other options that cannot be matched and are thus discarded) options [2] and [3]. The problem is that now, both options are templates, the first one can be resolved by matching CharT = char and traits = char_traits<char>, while the second can be matched by making T = const char* (the first argument is a concrete instantiated type). The compiler cannot make up its mind (there is no partial order that defines which option it should follow), and it triggers the ambiguity error.
The really interesting point in the question is that while both [1] and [2] seem to be templated on the arguments CharT and traits basically in the same way they are not considered in the same way by the compiler, the reason for that is that lookup finds [1] as a member of std::cout, that means that in [1], basic_ostream<char,char_traits<char> > is the concrete known type of the first argument and it is fixed. The template is the class, not the function, and the class instantiation types are fixed before lookup considers the member functions. On the other hand, when it ADL finds [2] and tries to match against the call, basic_ostream<CharT, traits> is a generic type that can be matched to the type of cout.
I hope this is not too confusing, but I think it is nice to know the subtle difference of similarly looking code.
I think that the problem is that in your header you've prototyped this function:
template <class Type>
ostream& operator<< (ostream& OutStream, const Type& OutList);
instead of this one:
template <class Type>
ostream& operator<< (ostream& OutStream, const list<Type>& OutList);
The version you've prototyped says that it's an operator << that can print out anything, not lists of anything. Consequently, when you write
cout << "Hello, world!" << endl;
The compiler can't tell which function it's supposed to call - the standard output function or the one you've defined in your list header.
declared as:
ostream& operator<< (ostream& OutStream, const Type& OutList);
in the function definition as:
ostream& operator<< (ostream& OutStream, const list<Type>& OutList)