C++ Templates Made Easy

Templates.

Groan.

With their godawful syntax and impressive verbosity it’s no wonder we screw our faces up in distaste when we see them in code. ESPECIALLY when we’re debugging that code. Oh my. It’s enough to make you wish you were writing the software for musical birthday cards instead (does anyone actually do that?).

Anyway, I’ve wanted to talk about templates for a long time but the approach is a tricky one because even hearing the dreaded ‘T’ word is enough to make people run for the hills. I probably should have put that in angle brackets. The dreaded <T> word. Ha ha.

Anyway, here we go, let’s dive in together because there is safety in numbers.

Templates – made easy. I promise 🙂

“Templates provide direct support for generic programming” – Bjarne Stroustrup

This is the basic concept of templates.

What does he mean by generic programming? Generic means non-specific. Generic programming deals with data in a general way, regardless of what that data is.

The absolute best way to explain templates is with a code example. There’s no avoiding it – you’ve got to face up to those angle brackets at some point, so it might as well be now.

Let’s start with a simple, ordinary (non-template) class called ‘Asset’. This class has a getter and a setter and that’s about it. It stores a standard string. Super-simple:

ifndef ASSET_H
define ASSET_H

#include <string>

class Asset {
public:
    Asset() {}
    ~Asset() {}

    std::string Get() {return name;}
    void Set(std::string n) {name = n;}

private:
    std::string name;
};

#endif /* ASSET_H */

Imagine we use this class to store the names of pieces of equipment in the office. We create a new object from this class for each piece of equipment that we want to register. The name might be “Lexmark” for our printer, or “Dell Inspiron” for a laptop. We can do this as follows:

#include <iostream>
#include "Asset.h" //the asset class listed above

using namespace std;

int main() {
    Asset item1;
    item1.Set("Lexmark");

    cout << item1.Get() << endl;

    return 0;
}

Now let’s imagine that we have a another printer in the office that has no branding on it. It’s a clunky old piece of equipment and no one knows who made it or where it came from. It just has the numbers “54633” printed on the front.

So, we could convert our number to a string and store it this way:

std::String printerNumber = "54633";
Asset item2;
item2.Set(numericMsg);

But, wouldn’t it be good if we could just pass a string OR a number directly to the Message class?

Oh yes it would.

Enter templates.

We can easily change our simple Asset class to be a more generic template class by adding this line above the class declaration:

template<class A>

Easy!

Now our class is a (almost) a template class. Before we move on though, let’s talk about the syntax, because that’s the thing that puts everyone off:

1. template

This is a c++ keyword (like int, or while), and it means exactly what it says. This code is defining a template.

2. <>

The infamous angle brackets. No, I don’t know why we have to use these either. Anyway, the angle brackets surround the name you are going to give the template. That’s all. No magic, no weird stuff, just a holder.

3. class A

This is your template type. The ‘class’ keyword can cause a bit of confusion here (see note 1 below). It doesn’t mean a ‘class’, it is simply a repurposing of the keyword class to mean your new type.

In a nutshell, the line above tells the compiler that what follows is a template that you have defined, called ‘A’.

Hold on, my code doesn’t compile.

Yep. There is one more step to complete in order to change your class to a template class.

You need to look through the body of the Asset class and change the old use of the specific type (std::string) to the new generic type A.

Huh?

Well, you’re creating a class that will deal with types generically – i.e. non-specifically. You can’t return a std::string from your Get function because you don’t know what kind of data (string/digits) the class will hold.

Instead you use the typename ‘A’ that you created in the template definition.

So that your Asset class now looks like this:

#ifndef ASSET_H_
#define ASSET_H_

template <class A>
class Asset {
public:
    Asset() {}
    virtual ~Asset() {}

    A Get() {return name;}
    void Set(A n) {name = n;}

private:
    A name;
};

#endif /* ASSET_H_ */

All clear?

Using a template

Now we can change the way we use the class.

To declare an instance we change the initialisation code in main.cpp to accommodate passing the type to the template:

#include <iostream>
#include "Asset.h"

using namespace std;

int main() {
    Asset<std::string> item1; //specify type here as string
    item1.Set("Lexmark");

    Asset<int> item2; //specify type here as int
    item2.Set(54633);

    cout << item1.Get() << endl;
    cout << item2.Get() << endl;

    return 0;
}

So, we have two Asset objects, but at heart they are different types: one is a string, the other is an an int.

To summarise

  • We created an Asset class that stored a string.
  • We wanted to use the same class to store a number.
  • We changed the Asset class to a template class that takes a type ‘A’ at initialisation.
  • Now we can create Asset objects that hold not only strings, ints, and doubles, but also other classes, enums or structs.

Right, that’s enough to get started. There are two more quick points I want to cover and then I suggest you go and make a template class of your own. Seriously – open that editor and create a class and then turn it into a template. Once you’ve done it yourself it will cement the concept in your mind and make it easier to follow the next part of the story.

Note 1: typename v class

You may have noticed, in your travels, that some templates are declared using typename instead of class:

template<typename T>
template<class T>

The C++ standard says:

14.1 There is no semantic difference between class and typename  in a template-parameter.

So you really don’t have to worry about this difference. I won’t go into the history here – for now just understand that either way is correct.

Note 2: A word about inheritance and templates

One of the first things you will be forgiven for thinking, having learnt about templates, is Whoa! Why did I spend all that time creating subclasses and inheritance when I could have just templated everything from one class!?

Good question.

But let’s look a little more closely:

A template contains generic methods that you can apply to any type of object you create with that template.

Whereas inheritance allows you to create subclasses that contain specialised methods relevant for a particular sub-object.

In the real world, you would use a template for processing different types of data in the same way (sorting it, printing it, storing it). Whereas you would use inheritance for creating specialised behaviour for a set of objects (calculations, movement, responsiveness), without necessarily applying that behaviour to ALL the objects you were dealing with.

2 thoughts on “C++ Templates Made Easy”

  1. Thanks for posting this.
    Could you also please explain the difference between Function Templates and Class Templates? Also how does compilers see the Templates? Does the body of all the functions gets created at compile time or Runtime? Can I have a Virtual Function inside a Templated Class?

    • Next week’s post covers Function Templates :-).

      Compilers create the source for template code at compile time – they only create a “version” for each template type that you create in your program, not for all possible types. As for virtual functions… you can have a virtual function inside a templated class, but you cannot have a virtual template function inside an ordinary class. The reason for this is down to how the compiler handles the vtable – I might do a post on it actually, but there is a discussion about this topic here that might help you: http://stackoverflow.com/questions/2354210/can-a-member-function-template-be-virtual

Comments are closed.