C++ Templates For Beginners

AID: 2014
  • Status: Published

2220 points

Awards
  • Community Pick
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;
}
                                    
1:
2:
3:

Select allOpen 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;
}
                                    
1:
2:
3:

Select allOpen 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;
}
                                    
1:
2:
3:
4:

Select allOpen 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;
}
                                    
1:
2:
3:
4:

Select allOpen 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;
}
                                    
1:
2:
3:
4:
5:
6:
7:

Select allOpen 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;
                                    
1:

Select allOpen 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);
                                    
1:
2:
3:
4:

Select allOpen 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;
}
                                    
1:
2:
3:

Select allOpen 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);
                                    
1:
2:

Select allOpen in new window



MyFile.cpp
SomeType myFunction(SomeType myVariable){
	return myVariable;
}
                                    
1:
2:
3:

Select allOpen 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;
}
                                    
1:
2:
3:
4:

Select allOpen 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);
}
                                    
1:
2:
3:
4:

Select allOpen 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);
                                    
1:
2:
3:
4:

Select allOpen 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);
                                    
1:

Select allOpen 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);
}
                                    
1:
2:
3:

Select allOpen 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);
                                    
1:

Select allOpen 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);
                                    
1:

Select allOpen 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;
                                    
1:

Select allOpen 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;
};
                                    
1:
2:
3:
4:
5:
6:
7:
8:
9:

Select allOpen 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
Asked On
2009-11-24 at 12:22:39ID2014
Tags

C++ Templates Beginner Function Class

Topic

C++ Programming Language

Views
988

Comments

Expert Comment

by: evilrix on 2009-11-25 at 11:40:55ID: 5966

Great article for beginners... received my "yes" vote above.

Expert Comment

by: mwvisa1 on 2009-11-25 at 12:25:14ID: 5967

I wholeheartedly agree, thank you very much!
Voted yes above, also.

Add your Comment

Please Sign up or Log in to comment on this article.

Join Experts Exchange Today

Gain Access to all our Tech Resources

Get personalized answers

Ask unlimited questions

Access Proven Solutions

Search 3.2 million solutions

Read In-Depth How-To Guides

1000+ articles, demos, & tips

Watch Step by Step Tutorials

Learn direct from top tech pros

And Much More!

Your complete tech resource

See Plans and Pricing

30-day free trial. Register in 60 seconds.

Loading Advertisement...

Top C++ Experts

  1. jkr

    261,219

    Guru

    1,000 points yesterday

    Profile
    Rank: Savant
  2. sarabande

    121,084

    Master

    3,800 points yesterday

    Profile
    Rank: Sage
  3. Infinity08

    54,855

    Master

    0 points yesterday

    Profile
    Rank: Genius
  4. ambience

    50,164

    Master

    0 points yesterday

    Profile
    Rank: Sage
  5. Zoppo

    48,382

    0 points yesterday

    Profile
    Rank: Genius
  6. evilrix

    48,358

    80 points yesterday

    Profile
    Rank: Genius
  7. satsumo

    22,400

    0 points yesterday

    Profile
    Rank: Guru
  8. tampnic

    19,040

    0 points yesterday

    Profile
    Rank: Master
  9. phoffric

    16,596

    0 points yesterday

    Profile
    Rank: Genius
  10. DanRollins

    16,330

    0 points yesterday

    Profile
    Rank: Genius
  11. duncan_roe

    14,400

    0 points yesterday

    Profile
    Rank: Genius
  12. gtokas

    12,700

    0 points yesterday

    Profile
    Rank: Wizard
  13. AndyAinscow

    12,132

    0 points yesterday

    Profile
    Rank: Genius
  14. mccarl

    9,600

    0 points yesterday

    Profile
    Rank: Wizard
  15. TommySzalapski

    8,800

    0 points yesterday

    Profile
    Rank: Genius
  16. pepr

    7,824

    0 points yesterday

    Profile
    Rank: Genius
  17. kaufmed

    7,168

    0 points yesterday

    Profile
    Rank: Genius
  18. Thommy

    6,700

    0 points yesterday

    Profile
    Rank: Wizard
  19. ubound

    6,550

    0 points yesterday

    Profile
    Rank: Master
  20. kuroji

    6,000

    0 points yesterday

    Profile
  21. for_yan

    6,000

    0 points yesterday

    Profile
    Rank: Genius
  22. mrwad99

    4,600

    0 points yesterday

    Profile
    Rank: Wizard
  23. masheik

    4,572

    0 points yesterday

    Profile
    Rank: Guru
  24. Orcbighter

    4,332

    0 points yesterday

    Profile
    Rank: Master
  25. ozo

    4,300

    0 points yesterday

    Profile
    Rank: Savant

Hall Of Fame