Overloading << for a template class

I've done some searching and tinkered with syntax, and it comes down to, I have no idea how to do this. Currently the function in question is a mess because I've spent some time just throwing things at it to see if anything sticks.

I've got a template linked-list style queue class and I need to overload <<. I want to be able to do things with it like say:
 
cout << aQueue;


or
 
outfile << aQueue;


and have it display all elements in the queue. I kind of need to overload the << operator instead of just returning a string, because I'm going to need to have queues of user-defined objects and work with their own << overloads.

Here's the header:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#ifndef Queue_h
#define Queue_h

#include <iostream>
using namespace std;

template <class Data>
class Queue{
private:
	struct Node {
		Data content;
		Node* next;
	};
	int length;
	Node* first;
	Node* last;
	

public:

	Queue();
//Default constructor, creates a new Queue object.

bool IsFull() const;
// Function: Determines whether queue is full.

bool IsEmpty() const;
//Determines whether queue is empty

int GetLength() const;
// Returns number of elements in queue

void RemoveFront();
//removes item from front of queue without returning anything

Data GetFront();
//returns the first item in the queue, removes first item in queue

Data ViewFront();
//Returns the first item in the queue without removing it.

void InsertItem(Data item);
// Function: Adds item to queue.

void MakeEmpty();
//Empties Queue


ostream operator<<(Queue<Data> theQueue);
//Display all items in queue.

~Queue();
//Destructor


};

#endif
#include "Queue.cpp" 


and the .cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
#ifndef Queue_cpp
#define Queue_cpp
#include "Queue.h"

#include <iostream>
using namespace std;

template <class Data>
Queue<Data>::Queue(){
	length = 0;
	first = NULL;
	last = NULL;
};

template <class Data>
bool Queue<Data>::IsFull()const{
	Node* location;
	try{
		location = new Node;
		delete location;
		return false;
	}
	catch(bad_alloc exception){
		return true;
	}
};

template <class Data>
bool Queue<Data>::IsEmpty()const{
	return (length == 0);
};

template <class Data>
int Queue<Data>::GetLength()const{
	return length;
};

template <class Data>
void Queue<Data>::RemoveFront(){
	if(length > 1){
		Node* placeholder = first;
		first = first->next;
		delete placeholder;
		length --;
	}
	else if(length == 1){
		delete first;
		first = NULL;
		last = NULL;
		length = 0;
	}
};

template <class Data>
Data Queue<Data>::GetFront(){
	Data placeholder = first->content;
	RemoveFront();
	return placeholder;
};

template <class Data>
Data Queue<Data>::ViewFront(){
	return first->content;
};

template <class Data>
void Queue<Data>::InsertItem(Data item){
	Node* newElementPtr;
	newElementPtr = new Node;
	newElementPtr->content = item;
	newElementPtr->next = NULL;

	if(length == 0){
		first = newElementPtr;
		last = newElementPtr;
	}
	else{
		last->next = newElementPtr;
		last = newElementPtr;
	}
	length++;
};

template <class Data>
void Queue<Data>::MakeEmpty(){
	while(length > 0){
		RemoveFront();
	}
};


template <class Data>
ostream Queue<Data>::operator<<(Queue<Data> theQueue){
	if(length > 0){
		Node* position = first;
		this << position->content << " ";
		while(position->next != NULL){
			position = position->next;
			this << position->content << " ";
		}
	}
	else{
		this << "Empty Queue";
	}
};


template <class Data>
Queue<Data>::~Queue(){
	while(length > 0){
		RemoveFront();
	}
};

#endif 


when I try to do something like...

 
cout << aQueue;


I get the error:
error C2679: binary '<<' : no operator found which takes a right-hand operand of type 'Queue<Data>' (or there is no acceptable conversion)...

I have no idea if I'm at all on the right track for what I want to do or if I should be starting again from scratch on this function.

I'm equally confused on how to do this if I make it a friend function instead.
Last edited on
You cannot list I/O operators as part of the class.

1
2
3
4
5
6
7
8
9
10
template <...>
class Foo
  {
  };

template <...>
ostream& operator << ( ostream& outs, const Foo& foo )
  {
  ...
  }

Good luck!
It seems like that would do it, except it's not a member function so it can't access data members in the Queue object it's supposed to be displaying.

The function looks like this right now:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
template <class Data>
ostream& operator<<(ostream& outs, const Queue<Data>& aQueue){
	if(aQueue.length > 0){
		Node* position = first;
		outs << position->content << " ";
		while(position->next != NULL){
			position = position ->next;
			outs << position->content << " ";
		}
	}
	else{
		outs << "Empty Queue";
	}

	return outs;
};


But if I try to make it a friend by putting this:
 
friend ostream& operator<<(ostream& outs, const Queue<Data> aQueue);


...in my .h I get the following error:

error LNK2019: unresolved external symbol "class std::basic_ostream<char,struct std::char_traits<char> > & __cdecl operator<<(class std::basic_ostream<char,struct std::char_traits<char> > &,class Queue<int>)" (??6@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@std@@AAV01@V?$Queue@H@@@Z) referenced in function _main

All I'm doing in main is

 
cout << aQueue;
Last edited on
I poked around a bit more and got this working. Since questions in this theme seem to come up quite a bit, here's what I was missing:

Even though the friend function is declared inside the class in the .h file, unlike the actual member functions it needs to be explicitly declared to be a template function.

so this:
 
friend ostream& operator<<(ostream& outs, const Queue<Data> aQueue);


Needed to be this:

1
2
template <class Data>
friend ostream& operator<<(ostream& outs, const Queue<Data> aQueue);



you must include your .cpp file in your main file.
@Paul2
Yes, you have it. It is not a member function, it is a friend, meaning you must also specify all the template stuff in the friend declaration prototype.

@SIK
No, don't do that. You should not ever #include .cpp files.
For templates, you have to include the .cpp file in the header (or simply not have a cpp file). When you #include "Queue.h" in another .cpp file, and create for example a Queue<int> object, the compiler needs to generate definitions for all of the functions in Queue<int>. Without the definitions of these functions available in Queue.h, the compiler would be unable to do this. In this case, the OP is including the implementation at the very bottom of Queue.h.
If you are going to include a ".cpp" file, it is better to call it something else.

MFC uses .inl for this purpose (for inline). I have also seen .icc and ixx used in the same way.
Last edited on
For templates, there isn't supposed to be a .cpp file; everything goes in the header (.h or .hpp or whatever -- not .cpp, etc).

The GCC uses ".tcc" for this kind of thing.
Point taken Duoas - putting template logic in a .cpp file is bad practice and also consequently will lead to the bad practice of needing to include those .cpp files.

Was just pointing out to Paul2 to include .cpp to get his project to compile from the position he was at.
Topic archived. No new replies allowed.