Compile Error

Started by
5 comments, last by toogreat4u 15 years, 3 months ago
I am trying to play around with templates and I am coming across a strange error and it is strictly related to using the ostream function function in header file:

#include <iostream>
using namespace std;

friend ostream& operator <<(ostream& outs, const GenericList<ItemType>& the_list);
	// Overlaods the << operator so it can be used to output the contents of the list.
	// The items are output one per line.
	// Precondition: If outs is a file output stream, then outs has already been connected to a file

function definition in cpp file:


#include <iostream>
#include <cstdlib>
#include "genericlist.h"

template<class ItemType>
ostream& operator <<(ostream& outs, const GenericList<ItemType>& the_list)
{
	for(int i = 0; i < the_list.current_length; i++)
		outs << the_list.item << endl;
	return outs;
}

This is how I am calling it in the driver file:

#include <iostream>
#include "genericlist.h"
#include "genericlist.cpp"
using namespace std;

GenericList<int> first_list(2);
	first_list.add(1);
	first_list.add(2);
	cout << "first_list = \n" << first_list;

It is giving me a link error and I am absolutely confused as to why: 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 GenericList<int> const &)" (??6@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@std@@AAV01@ABV?$GenericList@H@@@Z) referenced in function _main 1>C:\Documents and Settings\gdesigner\Desktop\Problem Solving with C++ 5th Edition\Chapter 14\Project 2\Debug\Project 2.exe : fatal error LNK1120: 1 unresolved externals 1>Build log was saved at "file://c:\Documents and Settings\gdesigner\Desktop\Problem Solving with C++ 5th Edition\Chapter 14\Project 2\Project 2\Debug\BuildLog.htm"
Advertisement
I assume the driver code is in some kind of function?

Either way, the issue is that on most compilers the template implementation must be available when you try to use it. More simply, if you leave the implementation in the header file it will work.

What is GenericList? Any reason you are avoiding the standard containers?
Thank you. Reason I am doing it this way is for learning purposes, plus its from a book and this is the way they designed there class structure.
Ok so the fix suggested didnt work so when I commented out the cout statements it compiled perfectly. I'll go ahead and show the whole header and definiton for genericlist, and the driver function.

Header:
#ifndef GENERICLIST_H#define GENERICLIST_H#include <iostream>using namespace std;template<class ItemType>class GenericList{public:	GenericList(int max);	// Initializes the object to an empty list that can hold up to max items of type ItemType		~GenericList();	// Returns all the dynamic memory used by the project to the freestore	int length() const;	// returns the number of items on the list	void add(ItemType new_item);	// Precondition: The list is not full	// Postcondition: the new_item has been added to the list	bool full() const;	// returns true if the list is full	void erase();	// removes all items from the list so that the list is empty	friend ostream& operator <<(ostream& outs, const GenericList<ItemType>& the_list);	// Overlaods the << operator so it can be used to output the contents of the list.	// The items are output one per line.	// Precondition: If outs is a file output stream, then outs has already been connected to a fileprivate:	ItemType *item;	// pointer to the dynamic array that holds the list	int max_length;	// max number of items allowed on the list	int current_length;	// number of items currently on the list};#endif


Definition file for GenericList
#ifndef GENERICLIST_CPP#define GENERICLIST_CPP#include <iostream>#include <cstdlib>#include "genericlist.h"using namespace std;template<class ItemType>GenericList<ItemType>::GenericList(int max): max_length(max), current_length(0){	item = new ItemType[max];}template<class ItemType>GenericList<ItemType>::~GenericList(){	delete [] item;}template<class ItemType>int GenericList<ItemType>::length() const{	return current_length;}template<class ItemType>void GenericList<ItemType>::add(ItemType new_item){	if(full())	{		cout << "Error: adding to a full list.\n";		exit(1);	}	else	{		item[current_length] = new_item;		current_length = current_length + 1;	}}template<class ItemType>bool GenericList<ItemType>::full() const{	return (current_length == max_length);}template<class ItemType>void GenericList<ItemType>::erase(){	current_length = 0;}template<class ItemType>ostream& operator <<(ostream& outs, const GenericList<ItemType>& the_list){	for(int i = 0; i < the_list.current_length; i++)		outs << the_list.item << endl;	return outs;}#endif


Driver program:
#include <iostream>#include "genericlist.h"#include "genericlist.cpp"using namespace std;int main(){	GenericList<int> first_list(2);	first_list.add(1);	first_list.add(2);	cout << "first_list = \n" << first_list;		GenericList<char> second_list(10);	second_list.add('A');	second_list.add('B');	second_list.add('C');	cout << "second list = \n" << second_list;	return 0;}
Quote:Source: Me
More simply, if you leave the implementation in the header file it will work.

Your template implementations aren't in the header file.

Quote:
Ok so the fix suggested didnt work...

What fix did you think I was talking about?
I think you really just can't put implementation of a template class in a separate cpp file.

Another thing is that friends to templates are a very tricky business.

Actually one would expect that your GenericList provides some kind of accessors, so that operator>> could be implemented as non-friend using the public interface of the container.
The fix I was referring to was the fix about placing all the defintions in the header file which still gave me the compiling errors. However the link visitor gave cleared up any of the confusion I had about what was going on. Thank you both for your responses. I simply defined the friend operator inside of the class.

friend ostream& operator <<(ostream& outs, const GenericList<ItemType>& the_list)	{		for(int i = 0; i < the_list.current_length; i++)			outs << the_list.item << endl;		return outs;	}


Is this a specific compiler issue with VC++ 2008? Because on a linux machine I never got this problem. Thanks for the help

This topic is closed to new replies.

Advertisement