<

Go Premium for a chance to win a PS4. Enter to Win

x

C++ Templates For Beginners

Published on
9,658 Points
3,258 Views
4 Endorsements
Last Modified:
Templates For Beginners

Or

How To Encourage The Compiler To Work For You


Introduction

This tutorial is targeted at the reader who is, perhaps, familiar with the basics of C++ but would prefer a little slower introduction to the more advanced topics. Although the material covered here is, indeed, about templates please don't think that this tutorial covers all you need to know. The subject of Templates is such a deep topic that complete books have been written about it; however, that's not to say this tutorial isn't complete, but that it will cover only the basic knowledge that you'll need...


What Are Templates And What Are They Used For?

Two good questions and perhaps the only ones that matter at the minute. To begin, let's start with what they're used for. Assume I asked you to write a function to add two integers together, you'd most likely come up with something like this:

int addTogether(int a, int b){
	return a+b;
}

Open in new window


If I then asked you to overload the function to add two doubles together, you would most likely overload the function as follows:

double addTogether(double a, double b){
	return a+b;
}

Open in new window


Now I then asked you to do the same for unsigned integers, strings and a few classes I wrote (which, no doubt, would be equally as useless as this addTogether function), you would probably be thinking two things. Firstly, you would be questioning my ability to reason correctly if I kept asking you to wrap a function around a simple add operation. Secondly, you'd be wondering if there was an easier way of writing such a function without having to overload it all the time. I cannot comment too much on the first point but the second point is exactly the reason for the existence of templates. They allow for a common piece of code to be used by all types of data; think of them as a magic overloaded function that works for any data type.


How To Make A Template

Before we go jumping into how to make templates we must first mention that there are two types of templates. The first type is called a function template while the second is called a class template; the differences between the two are negligible (for the purposes of this simple introduction), but as functions take less code than classes we will start with them. To begin with we'll just jump right in with what a templated function looks like using the addTogether function we used previously:

template<typename TType>
TType  addTogether( TType a,  TType b){
	return a+b;
}

Open in new window


The two main things you should have noticed is that we have replaced int with something called  TType and secondly we've got an extra line now starting with template. You may have to read this next part a couple of times over to ensure that you understand it.

In the first line (starting with template), we declare that the function to follow should use a template, we do this with the #template <># syntax just before the function definition. We then want our addTogether function to take all data types, so we do this by creating a substitute type which we call TType using the typename keyword. Now we've got this substitute type (which by the way only applies for this template), we can now use this data type inside the addTogether function, which we do by replacing the int with TType. Just an extra note, if you haven't picked up on it yet, rather than use TType we could call it anything we want.

Just to help explain this substitute idea, what happens when you use a template (we'll cover this shortly) is that the compiler actually replaces the template type (TType) with the type you create the template with. That may be a bit confusing so here's an example:

Here's our template:

template<typename TType>
TType  addTogether( TType a,  TType b){
	return a+b;
}

Open in new window


Here's what the compiler would create if we were to use an int and a double:

int addTogether( int a,  int b){
	return a+b;
}

double addTogether( double a,  double b){
	return a+b;
}

Open in new window


See, the substitute type, TType, is actually only a place-holder that doesn't have any meaning at all until the compiler comes along and replaces it with the specified type (in our cases int and double). The act of swapping the place-holder for real data types comes during the compilation phase - not the preprocessor phase, so all the rules and things of C++ aren't ruined when using this TType.

If you don't quite grasp all of this yet, don't worry, it's not difficult at all just a little strange at first. Keep reading and you'll pick it up...


How To Use Templates

If you've used the C++ STL (which you most likely have) you've already used a template. Consider a vector declaration:

vector<int> myVector;

Open in new window


That's how to use a class template (we'll cover them later on), although using a function template is even simpler, just use it like a normal function! Although notice that when we created the template, we used TType for the data type of both arguments, that means something like this:

unsigned int x=5;
int y=6;
unsigned int r=0;
r=addTogether(x, y);

Open in new window


wouldn't compile. Why? Because when the compiler comes to the addTogether function, it actually creates a copy of the function replacing TType we used with the type of the first argument, so it would end up with:

unsigned int addTogether(unsigned int a, unsigned int b){
	return a+b;
}

Open in new window


The issue we have is that the function expects an unsigned int for parameter b, but when we call this method (with the y variable), we are passing an int, so the compiler will complain that the data type of TType cannot be established.

The rules of splitting the declarations and definitions of templated functions and classes across header and source files can be a little confusing. For example, if we had:

MyFile.h:
template<typename SomeType>
SomeType myFunction(SomeType myVariable);

Open in new window


MyFile.cpp
SomeType myFunction(SomeType myVariable){
	return myVariable;
}

Open in new window


And we attempted to call myFunction from a separate source file, then we'd have problems, but calling it from the same source file will work fine. However if we had this:

MyFile.h:
template<typename SomeType>
SomeType myFunction(SomeType myVariable){
	return myVariable;
}

Open in new window


Then we would be able to call it from any source file we wanted. This is due to the fact the compiler must see the full template definition at the point it is instantiated but that is beyond the scope of this article. I highly recommend that you read the article given in the reference section on more information about this subject.


Using More Than One Type In Templates

Our templated addTogether function is, at the moment, a little limiting as we can only add together variables that are the same type, it would be nice to expand this so we can add together different types. Fortunately, this is quite easy to do. Let's say that we want to specify the data type of the return type as well as two function arguments. So, we need to expand the template so we can specify 3 data types. To do this we just add in a few more typenames as follows (although we'll name them better than TType):

template<typename returnType, typename firstType, typename secondType>
returnType addTogether(firstType a, secondType b){
	return (returnType)(a+b);
}

Open in new window


So now we should be able to do something such as:

unsigned int a=5;
int b=-10;
int r=0;
r=addTogether(a, b);

Open in new window


That should work right? Well, no not quite, how does the compiler know what type returnType should be, it has no way of working this out. What we want to do is specifically say that the return type should be an int, but before we do that, it is worth noting how exactly a created (or to use the correct word, instantiated) template knows what parameters are for what data type. When the compiler creates the template for us it uses left to right ordering to determine the types of parameters. For example, in our code above, specifically this line:

r=addTogether(a, b);

Open in new window


we pass in an unsigned integer and then an int, so using the template that we have above, the compiler would spit out code like the following:

returnType addTogether(unsigned int a, int b){
	return (returnType)(a+b);
}

Open in new window


So back to the previous code where we wish to specify a return type. You should see a problem here - the return type is undefined. The reason for this is when we call addTogether, the return data type is never specifically set. See, when we pass in an unsigned int (parameter a) and the int (parameter b), the compiler knows that unsigned int is meant for firstType and that int is meant for secondType, but the compiler never makes this automatic substitution for the return type, so we have to specify it manually. Remember the first line of code in the how to use the templates section, well we use that:

r=addTogether<int>(a, b);

Open in new window


What this is doing is saying that the first parameter of the template (returnType) should be of type int, and firstType and secondType the compiler can deduce from the types of the parameters a and b. If we were wanting to instantiate the template explicitly (which we have to do when using class templates), we could do this:

r=addTogether<int, unsigned int, int>(a, b);

Open in new window


but there is little need as the unsigned int and int for the second and third template parameters respectively are established from the two arguments we pass into addTogether.

...And on that note, we're done! You now have a solid foundation in function templates.


Class Templates

Class templates aren't too different from function templates, I assume you now understand function templates; if so this will be a breeze. A class template allows you to specify a class to work with many types. Take the std::vector for example:

std::vector<unsigned int> myVector;

Open in new window


If the vector was not templated then it would be very difficult and tedious to use a vector with any type. Creating a class template is as easy as:

template<typename TMyType>
class CMyClass{
public:
	void setMyVariable(TMyType aVariable){
		myVariable=aVariable;
	}
private:
	TMyType myVariable;
};

Open in new window


Quite a useless example, but nonetheless an example demonstrating a class template. Note that for the entirety of CMyClass the typename TMyType exists, so we don't need to define it again for the setMyVariable method. As for using class templates, just see the top line in this section showing how you create a std::vector variable.

Well you're done! You should now have a basic grasp of templates. As I stated in the introduction, there is so much more to templates that haven't even had a mention, but you'll be pleased to know the hardest part in getting the groundwork is complete. Have fun with generic programming!


References

Title: Separating C++ template declaration and implementation.
Author: EvilRix
Link: http://www.experts-exchange.com/A_1199.html
Summary: While in this article I simply mentioned that the template declaration and implementation cannot be separated, I never explained in any detail the technical reasons for this, should you wish to know the details behind this I highly recommend reading the above article, if only to reinforce the knowledge you have already gained.

Further tutorials on templates:
http://www.cplusplus.com/doc/tutorial/templates/
http://www.cprogramming.com/tutorial/templated_functions.html
http://www.cprogramming.com/tutorial/templates.html
4
Comment
2 Comments
 
LVL 40

Expert Comment

by:evilrix
Great article for beginners... received my "yes" vote above.
0
 
LVL 60

Expert Comment

by:Kevin Cross
I wholeheartedly agree, thank you very much!
Voted yes above, also.
0

Featured Post

Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Join & Write a Comment

The viewer will learn how to user default arguments when defining functions. This method of defining functions will be contrasted with the non-default-argument of defining functions.
The viewer will be introduced to the technique of using vectors in C++. The video will cover how to define a vector, store values in the vector and retrieve data from the values stored in the vector.
Suggested Courses
Next Article:

Keep in touch with Experts Exchange

Tech news and trends delivered to your inbox every month