Hello,

I am trying to implement a linked list with an h file that was provided to me, which I cannot change. I have created a simple main() to begin, but I am getting an error on line 40 of the h file that says...

"template-id 'operator<< <int>' for 'std::ostream& operator<<(std::ostream&, const List<int>&)' does not match any template declaration"

#include "utility.h"
#include "lnklist.h"

using namespace std;

int main()
{
    List<int> myList;
}
#ifndef lnklist_h
#define lnklist_h
//singly linked list class

template <class T>
struct Node
{
	Node() { next = NULL;};		// constructor
	T value;					// data stored in a node
	Node<T> *next;				// pointer to next node
};

// List template, implemented as a linked list.
// All insertion and deletion is done at the current position in the list.

template <class T>
class List
{
		
public:
	List();								// Construct an empty list.
	~List();							// destructor
	void Clear();
	
	void InsertBefore(T e);				// Insert e before current position
	void InsertAfter(T e);				// Insert e after current position
	void Remove();						// Delete the node at the current position
	
	void Head(); 						// Move current location to the head
	void Tail(); 						// Move current location to the tail
	
	List<T>& operator++ (int);			// Move current to next position (postfix)
	List<T>& operator-- (int);			// Move current to prior position (postfix)
	
	T Retrieve() const;					// Return the element at the current position
	void Update(T e);					// Store e in current location

	
	int Length() const;					// Return the size of the list
	friend ostream& operator<< <T>(ostream& os, const List<T>& s);  //Output a list

		
protected:
	Node<T>  *first,					// pointer to the first node in the list
		     *current,					// pointer to current node
			 *last;						// pointer to the last node in the list
	int	size;							// number of elements in the list
};
#endif

//----------------- Definition of LinkedList member functions and friends

template <class T>
ostream& operator << (ostream& os, const List<T>& s)
// Output an entire list, from first position to last.
{
	Node<T> *p = s.first;
	while (p != NULL)
	{
		os << p->value << " ";
		p = p->next;
	}
	return os;
}

template <class T>
List<T>::List()
// Default constructor.  Builds an empty list.
{	
	first = current = last = NULL;
	size = 0;
}


template <class T>
List<T>::~List()
// destructor
{
	Clear();
}

template <class T>
void List<T>::Clear()
// empty the list
{
	Node<T> *nptr = first;
	current = first;
	while (current != NULL)
	{
		current = current->next;
		delete nptr;
		nptr = current;
	}
	first = current = last = NULL;
	size = 0;
}

template <class T>	
void List<T>::InsertBefore(T e)
// Insert e at the current position.
{
	Node<T> *nptr = new Node<T>;

	if (size == 0)
	{
		// Inserting into an empty list
		nptr->value = e;
		nptr->next = NULL;
		first = current = last = nptr;
	}
	else
	{
		// Inserting into an non-empty list.
		nptr->value = current->value;
		nptr->next = current->next;
		current->next = nptr;
		current->value = e;
		if (current == last)
			last = nptr;
	}
	size++;
}

template <class T>
void List<T>:: InsertAfter(T e)
// Insert e after the current position.
{
	// Construct a new node and fill it
	// with the appropriate value
	Node<T> *nptr = new Node<T>;
	nptr->value = e;

	if (size == 0)
	{
		// Inserting into an empty list.
		nptr->next = NULL;
		first = current = last = nptr;
	}
	else
	{
		// Inserting into an non-empty list.
		nptr->next = current->next;
		current->next = nptr;
		if (current == last)
			last = nptr;
		current = nptr;
	}
	size++;
}

template <class T>
void List<T>::Remove()
// Delete the node at the current position.
// If the list is empty, display a warning, but continue working.
{
	Node<T> *nptr;
	if (size == 0)
	{
		cout << "Attempt to Remove an element from an empty list" << endl;
		return;
	}
	else if (size == 1)
	{
		// Remove the only node in the list
		delete current;
		first = current = last = NULL;
	}
	else if (current == last)
	{
		// Remove the last node of a list that has more than one node.
		nptr = first;
		// Find predecessor to current node.
		while (nptr->next != current)
			nptr = nptr->next;
		nptr->next = current->next;
		delete current;
		current = last = nptr;
	}
	else
	{
		// Remove a node that's not the last one.
		nptr = current->next;
		current->value = nptr->value;
		current->next = nptr->next;
		if (last == nptr)
			last = current;
		delete nptr;
	}
	size--;
}

template <class T>	
void List<T>::Head()
// Move current location to the head.
{ 
	current = first;
}
	
template <class T>
void List<T>::Tail()
// Move current location to the tail.
{
		current = last;
}

	
template <class T>
List<T>& List<T>::operator++ (int)
// Move current location to next node (postfix operator).
// Do nothing if current is at the tail of the list.
{
	if (current != last)
		current = current->next;
	return *this;
}

template <class T>
List<T>& List<T>::operator-- (int)
// Move current location to previous node (postfix operator).
// Do nothing if current is at the head of the list
{
	if (current != first)
	{
		Node<T> *nptr = first;
		while (nptr->next != current)
			nptr = nptr->next;
		current = nptr;
	}
	return *this;
}

template <class T>	
T List<T>::Retrieve() const	
// Return the element at the current position.
// Quit the program if the list is empty, since we can't return anything.
{
	if (size <= 0)
	{
		cout << "Cannot Return an element from an empty list";
		exit(1);
	}
	return current->value;
}

template <class T>
void List<T>::Update(T e)
// Store e in current location.
// Quit the program if the list is empty.
{
	if (size > 0)
		current->value = e;
	else
	{
		cout << "Cannot Update an element in an empty list";
		exit(1);
	}
}


template <class T>
int List<T>::Length() const
// Return the number of elements in the list.
{ 
	return size;
}

This right here

friend ostream& operator<< <T>(ostream& os, const List<T>& s);

is invalid syntax. It should be

friend ostream& operator<< (ostream& os, const List<T>& s);

Also make sure your implementation of the List is in the same file as the definition, since its templatized.

Edited 5 Years Ago by firstPerson: n/a

Also make sure your implementation of the List is in the same file as the definition, since its templatized.

Does this mean the h file must be in the same project?

Thanks for the help with the syntax.

Does this mean the h file must be in the same project?

Thanks for the help with the syntax.

No doesn't have to be in the same project, its just that usually people separate the class interface from its implementation in different files. If the class is templatized then as of right now you cannot seperate the interface from the implementation into multiple files. The header file( .h ) can be any where as long as you link it properly.

friend ostream& operator<< <T>(ostream& os, const List<T>& s);

versus

friend ostream& operator<< (ostream& os, const List<T>& s);

I appreciate your help with the syntax, but there must be a way to use the original code in the h file. I agree, if I remove the <T>, the program works. The h file was provided by my instructor, and several students have turned the assignment in without mentioning this problem. Is it possible I that I need to invoke the program differently in main()?

Edited 5 Years Ago by coolbeanbob: n/a

what compiler are you using? I think the original might be a valid syntax. Either way report it to your instructor

Edited 5 Years Ago by firstPerson: n/a

I'm using GNU GCC. We are supposed to be using Visual Studio 2008. I'm more used to codeblocks and I have not forced myself to making the switch. I should probably do so.

I actually started this project using VS, but every time I tried to compile I received an error saying it could not find my file.

friend ostream& operator<< <T>(ostream& os, const List<T>& s);

This is line 125. What is "T" and "s" here? I'm assuming "os" is the ostream object?

The "<T>" just means its not a specialized for any types, hence applies to all instance. The "os" and "s"
are just object parameter.

How can I call this function? Or should I say it is even a function? The rest of the declarations have function names (i.e. void List<T>:: InsertAfter(T e))

I don't really understand what this is. I would like to call it as a function, because I need to print the entire list.

template <class T>
ostream& operator << (ostream& os, const List<T>& s)
// Output an entire list, from first position to last.
{
	Node<T> *p = s.first;
	while (p != NULL)
	{
		os << p->value << " ";
		p = p->next;
	}
	return os;
}

Edited 5 Years Ago by coolbeanbob: n/a

It is a function. It's name is operator<<, and you could in fact call it as, for instance, operator<<(cout, myList); . But it's name makes it a special kind of function which overloads the "<<" operator, so that you can more naturally specify cout << myList; .

You can overload mathematical operators for your own classes as well, so that if you were to create (for instance) a rational-number class:

class Rational
{
protected:
  int numerator;
  int denominator;
public:
  Rational(n, d);
  ~Rational();
  Rational operator*(const Rational & other) const;
  ...
};

...

Rational Rational::operator*(const Rational & other) const
{
  int n = numerator * other.numerator;
  int d = denominator * other.denominator;
  return Rational(n, d);
}

...

int main(int argc, char * argv[])
{
   ...
   Rational r1 (3, 5);  // r1 = 3/5
   Rational r2 (4, 7);
   Rational r3 = r1 * r2;  // invokes Rational::operator*()
   ...
}

Edited 5 Years Ago by raptr_dflo: const tweak

This article has been dead for over six months. Start a new discussion instead.