Learning Templates

Hi all,

I have started to learn templates and I am having a few issues with compilation and linking errors. After a little research with Google, I found that I should do one of two things: either include a *.cpp file or place the function definitions in my header file for the class in which I am trying to define. I also read that including a *.cpp file is a really bad practice. Also, is it bad to place the definitions in a header file, should do this, and the bigger question, why? I am hoping that someone with more experience and background can look at this and tell me the hows, whys and so forth. I would also like to see a simple example if at all possible. Thank you in advance for any and all help as well as for your time.

File: Generic List.h
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
#ifndef GENERICLIST_H
#define GENERICLIST_H

namespace list
{
	template<class ItemType>
	class GenericList
	{
		public:
			GenericList(int maxSize);
			~GenericList();
			int length() const;
			bool full() const;
			friend std::ostream& operator<<(std::ostream &ostr, const GenericList<ItemType> &list)
			{
				for(int i = 0; i < list.currentLength; i++)
					ostr << list.item[i] << std::endl;
				return ostr;
			}
			void add(ItemType newItem);
			void erase();

		private:
			ItemType *item;
			int maxLength;
			int currentLength;
	};
}

#endif 


File: Generic List.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
#include <iostream>
#include <cstdlib>
#include "Generic List.h"

namespace list
{
	template<class ItemType>
	GenericList<ItemType>::GenericList(int maxSize) : maxLength(maxSize), currentLength(0)
	{
		item = new ItemType[maxLength];
	}

	template<class ItemType>
	GenericList<ItemType>::~GenericList()
	{
		delete [] item;
	}
	
	template<class ItemType>
	int GenericList<ItemType>::length() const
	{
		return currentLength;
	}

	template<class ItemType>
	bool GenericList<ItemType>::full() const
	{
		return (currentLength == maxLength);
	}
	
	template<class ItemType>
	void GenericList<ItemType>::add(ItemType newItem)
	{
		if(full())
		{
			std::cout << "Error: Adding to a full list.\n";
			char ch;
			std::cin.get(ch);
			exit(1);
		}

		item[currentLength] = newItem;
		currentLength++;
	}

	template<class ItemType>
	void GenericList<ItemType>::erase()
	{
		currentLength = 0;
	}
}


File: Main.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <iostream>
#include "Generic List.cpp" //Or #include "Generic List.h

using namespace std;
using namespace list;

int main()
{
	char ch;
	GenericList<int> firstList(2);



	cin.get(ch);
	return 0;
}
The stl classes are declared and implemented in a single header file, so this might be a good example to follow.
One example:
https://www.sgi.com/tech/stl/string
When dealing with templates, both the definitions and the implementations must be in the same compilation unit.

I found that I should do one of two things: either include a *.cpp file or place the function definitions in my header file for the class in which I am trying to define.

Normally including source files in headers is a bad practice but it is acceptable when dealing with templates. However many people would recommend changing the file extension to something other than .cpp. For example use .inc instead of .cpp.

Also, is it bad to place the definitions in a header file, should do this, and the bigger question, why?

When dealing with template classes it is quite normal to end up with a header only "library". For the why please read the first paragraph.
Topic archived. No new replies allowed.