Navigation



14.1 — Function templates

The need for function templates

In previous chapters, you’ve learned how to write functions and classes that help make programs easier to write, safer, and more maintainable. While functions and classes are powerful and flexible tools for effective programming, in certain cases they can also be somewhat limiting because of C++’s requirement that you specify the type of all parameters.

For example, let’s say you wanted to write a function to calculate the maximum of two numbers. You might do so like this:

int max(int nX, int nY)
{
    return (nX > nY) ? nX : nY;
}

This function would work great — for integers. What happens later when you realize your max() function needs to work with doubles? Traditionally, the answer would be to overload the max() function and create a new version that works with doubles:

double max(double dX, double dY)
{
    return (dX > dY) ? dX : dY;
}

Note that the code for the implementation of the double version of maximum() is exactly the same as for the int version of max()! In fact, this implementation would work for all sorts of different types: chars, ints, doubles, and if you’ve overloaded the > operator, even classes! However, because C++ requires you to make your variables specific types, you’re stuck writing one function for each type you wish to use.

Having to specify different “flavors” of the same function where the only thing that changes is the type of the parameters can become a severe maintenance headache and time-waster, and it also violates the general programming guideline that duplicate code should be minimized as much as possible. Wouldn’t it be nice if we could write one version of max() that was able to work with parameters of ANY type?

This is where function templates come in!

What is a function template?

If you were to look up the word “template” in the dictionary, you’d find a definition that was similar to the following: “a template is a model that serves as a pattern for creating similar objects”. One type of template that is very easy to understand is that of a stencil. A stencil is an object (eg. a piece of cardboard) with a shape cut out of it (eg. the letter J). By placing the stencil on top of another object, then spraying paint through the hole, you can very quickly produce stenciled patterns in many different colors! Note that you only need to create a given stencil once — you can then use it as many times as you like to create stenciled patterns in whatever color(s) you like. Even better, you don’t have to decide the color of the stenciled pattern you want to create until you decide to actually use the stencil.

In C++, function templates are functions that serve as a pattern for creating other similar functions. The basic idea behind function templates is to create a function without having to specify the exact type(s) of some or all of the variables. Instead, we define the function using placeholder types, called template type parameters. Once we have created a function using these placeholder types, we have effectively created a “function stencil”.

It turns out that you can’t call a function template directly — this is because the compiler doesn’t know how to handle placeholder types directly. Instead, when you call a template function, the compiler “stencils” out a copy of the template, replacing the placeholder types with the actual variable types in your function call! Using this methodology, the compiler can create multiple “flavors” of a function from one template! We’ll take a look at this process in more detail in the next lesson.

Creating function templates in C++

At this point, you’re probably wondering how to actually create function templates in C++. It turns out, it’s not all that difficult.

Let’s take a look at the int version of max() again:

int max(int nX, int nY)
{
    return (nX > nY) ? nX : nY;
}

Note that there are 3 places where specific types are used: parameters nX, nY, and the return value all specify that they must be integers. To create a function template, we’re going to replace these specific types with placeholder types. In this case, because we have only one type that needs replacing (int), we only need one template type parameter. Let’s call our this placeholder type “Type”. You can name your placeholder types almost anything you want, so long as it’s not a reserved word. Here’s our new function with a placeholder type:

Type max(Type tX, Type tY)
{
    return (tX > tY) ? tX : tY;
}

(Note: I also changed the Hungarian notation on the variables to reflect that they are not necessarily integers any longer — they are whatever type Type is!)

This is a good start — however, it won’t compile because the compiler doesn’t know what “Type” means! In order to tell the compiler that Type is meant to be a placeholder type, we need to formally tell the compiler that Type is a template type parameter. This is done using what is called a template parameter declaration:

template <typename Type> // this is the template parameter declaration
Type max(Type tX, Type tY)
{
    return (tX > tY) ? tX : tY;
}

Believe it or not, we’re done! This will compile!

Now, let’s take a slightly closer look at the template parameter declaration. We start with the keyword template — this tells the compiler that what follows is going to be a list of template parameters. We place all of our parameters inside angled brackets (<>). To create a template type parameter, use either the keyword typename or class. There is no difference between the two keywords in this context, and you will usually see people use the class keyword. However, we prefer the newer typename keyword, because it makes it clearer that the template type parameter doesn’t have to be a class. After the typename or class keyword, all that’s left is to pick a name for your placeholder type. Traditionally, with function that have only one template type parameter, the name “Type” (often shortened to “T”) is used. If the template function uses multiple template type parameter, they can be separated by commas:

template <typename T1, typename T2>
// template function here

Using function templates

Using a function template is extremely straightforward — you can use it just like any other function:

int nValue = max(3, 7); // returns 7
double dValue = max(6.34, 18.523); // returns 18.523
char chValue = max('a', '6'); // returns 'a'

Note that all three of these calls to max() have parameters of different types!

As you can see, template functions can save a lot of time, because you only need to write one function, and it will work with many different types. Once you get used to writing function templates, you’ll find they actually don’t take any longer to write than functions with actual types. Template functions reduce code maintenance, because duplicate code is reduced significantly. And finally, template functions can be safer, because there is no need to copy functions and change types by hand whenever you need the function to work with a new type!

Template functions do have a few drawbacks, and we would be remiss not to mention them. First, older compilers generally do not have very good template support. However, modern compilers are much better at supporting and implementing template functionality properly. Second, template functions produce crazy-looking error messages that are much harder to decipher than those of regular functions. However, these drawbacks are fairly minor compared with the power and flexibility templates bring to your programming toolkit!

Note: The standard library already comes with a templated max() function. If you use the statement “using namespace std;” the compiler will be unable to tell whether you want your version of max() or std::max().

14.2 — Function template instances
Index
13.7 — Random file I/O

14 comments to 14.1 — Function templates

  • Bruce

    The usage of template should be

    template
    //template function here
    

    or I misunderstood something here?

  • 2nd code part:

    int max(double dX, double dY)
    {
        return (dX > dY) ? dX : dY;
    }
    

    the return should be a double not an int, so:

    double max(double dX, double dY)
    {
        return (dX > dY) ? dX : dY;
    }
    

    is better

    [ Yes, thank you. It's fixed now. -Alex ]

  • Abhijit Yelegaonkar
     Alex, We will always be in awe of u for this excellent tutorial...God Bless u...
  • Have you guys realized that once you declare “using namespace std;” in the beginning of your code….There will be multiple errors in the code if you try to use the template.

    For example:

    using namespace std;
    
    template  // this is the template parameter declaration
    Type max(Type tX, Type tY)
    {
        return (tX > tY) ? tX : tY;
    }
    
    int main()
    {
    	int nValue = max(3, 7); // returns 7
    	double dValue = max(6.34, 18.523); // returns 18.523
    	char chValue = max('a', '6'); // returns 'a'
    	cout << nValue << " " << dValue << " " << chValue << endl;
    	return 0;
    }
    

    This creates an error while this doesn’t:

    template  // this is the template parameter declaration
    Type max(Type tX, Type tY)
    {
        return (tX > tY) ? tX : tY;
    }
    
    int main()
    {
    	int nValue = max(3, 7); // returns 7
    	double dValue = max(6.34, 18.523); // returns 18.523
    	char chValue = max('a', '6'); // returns 'a'
            using namespace std;
    	cout << nValue << " " << dValue << " " << chValue << endl;
    	return 0;
    }
    

    [ This is because the local version of max() has a namespace collision with std::max(). I made a note of it at the bottom of the article. Thanks for the heads up. -Alex ]

  • Puneet
    Many people are not able to explain things in such a clear way.. This is really helpful.. Thanks... 
  • karmeloz

    when we use the keyword “template”, we tell the compiler that what follows is going to be a list of template parameters.
    so why do we need the additional keyword typename (or class) for each parameter ? is the keyword typename redudantant
    or does it have a specific function? thanks, Karmeloz

  • Can you define these Template functions in seperate cpp files and have the definition in a .h file like normal functions?

    // .h file def
    template <typename T>
    int GetArrayLength(T iArray[]);
    
    // .cpp file function
    template <typename T> // this is the template parameter declaration
    int GetArrayLength(T iArray[])
    {
    	return sizeof(iArray) / sizeof(iArray[0]);
    }
    

    If i then use the GetArrayLength() function from my main.cpp, I get the following build errors:

    Error	1	error LNK2019: unresolved external symbol "int __cdecl GetArrayLength<int>(int * const)" (??$GetArrayLength@H@@YAHQAH@Z) referenced in function _wmain	CPPTest.obj	CPPTest
    Error	2	fatal error LNK1120: 1 unresolved externals	CPPTest.exe	1	CPPTest
    

    If I just define the function twice (once in my helper.cpp and once in my main.cpp), everything works as expected. Any idea what’s wrong here?

    • I found your commend in chapter 14.3

      A note for users using older compilers
      
      Some older compilers (eg. Visual Studio 6) have a bug where the definition of template class functions must be put in the same file as the template class is defined in. Thus, if the template class were defined in X.h, the function definitions would have to also go in X.h (not X.cpp). This issue should be fixed in most/all modern compilers.
      

      I am afraid this is still the case with Visual Studio 2008; if I just completely define the function in the .h file, it works as expected.

      • Slice

        I’m running Microsoft Visual Studio 2008 Professional Edition, Version 9.0.21022.8 RTM with .NET Framework, Version 3.5 SP1, and I can confirm that it still doesn’t allow you to split a template into the typical header and source file arrangement. In order to get templates to work in that environment, one must still code the entire template definition inside the header file :(.

        On the up side: my 1st linker error in the whole tutorial. W00!

        Oh, and great tutorial Alex (if you still read these). I even stopped reading the book I was reading on C++ about halfway through and totally moved onto this and even started doing some graphics work at the same time because the information presented here was so clear and concise albeit littered with “it’s” when they should have been “its” :P. I will go back and finish the book at some point just in case I missed anything, but in the mean time onward I go.

  • Clarisse

    The person who writes n this blog must be really happy with happy feelings =)

  • mslade

    It seems like template functions can violate encapsulation. In your max() example, client code needs to know that it uses the > operator, and that operator>(the_type, the_type) needs to be defined for it to work.

    Is there a way around this or am I just wrong?

You must be logged in to post a comment.