In the previous chapter, we had a brief encounter with function templates. In this chapter, we will learn how to implement a function template. We will use the phrases “template function” and “function template” interchangeably throughout this book. For all practical purposes, there is no difference between the two (The C++ Programming Language, Bjarne Stroustrup, 2013). Template functions are an excellent tool for writing generic algorithms. However, the syntax of the function template may look quite intriguing. So, we will break it down and try to untangle it step by step.
By the end of this chapter, you will learn the general syntax of a function template, use the syntax, and define your function template. You will understand how the compiler processes the template function in two separate steps. Then we will examine the automatic template function instantiation process by the compiler along with explicit and implicit instantiation of the same. Finally, we will see how we can create a separate namespace to avoid name conflict with any other function template either in the STL library or in the global namespace.
Please check the following Github repository for the source codes used in this chapter: Source Code Chapter 2.
Syntax of a function template
Let’s have a look at the syntax of a single parameter function template:

A template function declaration starts with the keyword template. This is followed by an opening angle bracket (<) indicating the start of the declaration of template parameter(s). The keyword typename follows the angle bracket and then the name of the template parameter. The name of the template parameter can be any name. However, T is historically a popular name as a template parameter.
There can be single or multiple template parameters in a function template definition. After declaring all the template parameters, we close the parameter list using the closing angle bracket (>). In Figure 2.1, there is only one template parameter T. You can also use the keyword class instead of typename; there is no difference between them. I prefer the keyword typename over class as it gives more clarity.
T is like any built-in or user-defined data type in the rest of the function body. We can use in the following ways:
- for specifying the function template’s return type
- for specifying type of function arguments
- in the function template body to declare any variable like any built-in or user-defined data type
We will learn how to use all the information the syntax when we write our first function template in the next section.
Writing a function template
Now that know the syntax of a function template, let us write our first function template as follows:
#include <iostream>
template<typename T>
T abs(T myvar)
{
return myvar > 0 ? myvar : (-myvar);
}
int main()
{
double dVar = -20.5;
std::cout << abs(dVar) << std::endl;
int iVar = 10;
std::cout << abs<>(iVar) << std::endl;
char cVar = 'A';
std::cout << abs(cVar) << std::endl;
return 0;
}
In this example, we have defined a function template abs(). The template declaration starts with the keyword template, followed by an opening angle bracket (<). Then we specified the keyword typename followed by the template parameter name T and then a closing angle bracket (>). T represents the type of function argument (myvar in this case). Notice, we also used T to declare the return type of abs(). In the main() function, we have first passed a negative argument of type double (dVar), then a positive integer argument (iVar), and finally a char type argument (cVar) to the abs() function template. If you compile and run the program, you will see an output as follows:
$ g++ abs.cpp -o abs -Wall -Werror
$ ./abs
20.5
10
A
We have added some additional compiler flags to compile this program. The following are good to have flags that help in identifying programmatic errors that may lead to unwarranted bugs:
- -Wall: This enables all the warnings during compilation. This flag only reports potential errors but will not break the compilation.
- -Werror: This turns all warnings into errors and break the compilation. I would recommend using this flag for all future compilations.
When the function template is called with template arguments, the compiler deduces the type of the arguments and binds with T. Then, the compiler creates an instance of the function template, replacing T with the deduced type. In the next section, we will learn how the compiler processes function templates.
Two-phase compilation
The compiler processes the template function in two phases. This is a topic that may vary slightly from compiler to compiler. Usually in the first phase of lookup, the compiler looks into the template function definition for syntactical errors and unknown symbols but does not check the template function parameters or any other programmatic errors.
In the second phase, when the template function is called from the program, the compiler verifies the template parameters and overall validity of the template code. If the compiler finds any mismatch in the parameters or finds any other programmatic discrepancy, it reports an error. The following diagram shows the lookup process phases:

Let’s have a look at the following code:
#include <iostream>
struct foo_struct {
int a;
};
template<typename T>
void foo(T& mystruct)
{
std::cout << "a = " << mystruct.c << std::endl
}
int main()
{
std::cout << "Hello World" << std::endl;
return 0;
}
This program has defined a struct data type foo_struct, which has a member variable a of type int. In the foo() template function definition, we have deliberately left two errors: firstly we have omitted a semicolon in the foo() template body, and secondly, we referred to a member variable c of the struct foo_struct data type, which does not exist. Now, if you try compiling this code, you will see the following error:
two_phase_lookup.cpp: In function 'void foo(T&)':
two_phase_lookup.cpp:11:1: error: expected ';' before '}' token
The compiler is only compiling about the missing semicolon (that is, the first error) but not the second error. Missing the semicolon is a syntactical error that the compiler has detected. The compiler is not complaining about the second error (a logical error) because we have not called the template function foo() in main(). As a result, the compiler has not checked for any code validity. Let us correct the semicolon in the foo() template function body as shown:
void foo(T& mystruct)
{
std::cout << "a = " << mystruct.c << std::endl;
}
Now, if you recompile the program, there will be no error. As the function template was not called, the compiler didn’t go into the second phase of lookup. To force the compiler to do the second phase of compilation, we have to call the function template foo() in the main() to enforce instantiation. To do that we will change the previous program’s main() function as follows to call foo():
#include <iostream>
struct foo_struct {
int a;
};
template<typename T>
void foo(T& mystruct)
{
std::cout << "a = " << mystruct.c << std::endl;
}
int main()
{
foo_struct mystruct{10};
foo(mystruct);
return 0;
}
If you compile the previous program, you will see the following compilation error:
$ g++ two_phase_lookup.cpp -Wall -Werror -o two_phase_lookup
two_phase_lookup.cpp: In instantiation of 'void foo(T&) [with T = foo_struct]':
two_phase_lookup.cpp:16:17: required from here
two_phase_lookup.cpp:10:37: error: 'struct foo_struct' has no member named 'c'
std::cout << "a = " << mystruct.c << std::endl;
Because we have called the template function foo() with the foo_struct type object, the compiler is trying to create an instance of the template function using foo_struct type. In this second phase compilation, the compiler found no member c in the foo_struct and hence the error. To eliminate the error, we should replace the member c (which doesn’t exist) with the member a as follows:
template<typename T>
void foo(T& mystruct)
{
std::cout << "a = " << mystruct.a << std::endl;
}
The second phase of the compilation of the template is related to instantiation. We will learn more about instantiation in the next section.
Function template instantiation
In the previous chapter, we have seen a conceptual model of function template instantiation. Here, we will go a little deeper into it and see how and when the compiler generates the various instances of the template internally with different data types. There are two ways to instantiate function templates, which we will discuss in the following sections.
Implicit instantiation
Whenever we call the function template with a set of data types different from all the previous occurrences, the compiler implicitly creates a new instance of the template with the actual data type passed in the argument. This is known as instantiation or implicit instantiation. Let’s, look at the following example:
#include <iostream>
template<typename T>
void swap(T& x, T& y)
{
T temp;
temp = x;
x = y;
y = temp;
}
int main()
{
int var1 = 10, var2 = 20;
std::cout << "Before: var1 = " << var1 << " var2 = " << var2 << std::endl;
swap(var1, var2);
std::cout << "After: var1 = " << var1 << " var2 = " << var2 << std::endl;
double var3 = 40.5, var4 = 20.5;
std::cout << "Before: var3 = " << var3 << " var4 = " << var4 << std::endl;
swap(var3, var4);
std::cout << "After: var3 = " << var3 << " var4 = " << var4 << std::endl;
return 0;
}
Compile the previous code as shown:
$ g++ template_instance_swap.cpp -o template_instance_swap -Wall -Werror
In the previous program, we have defined a template function that takes two arguments of type T and swaps their value. In the main() function, we have called the template function swap() twice: first with two integers and the second time with two doubles. As we discussed before, the compiler will generate two versions of the template function swap(), one with integers and one with doubles. The pictorial representation of the compiler instantiation is as follows:

To examine the compiler generated instances, we will use the tool nm in Linux command line as follows:
$ nm -C template_instance_swap | grep -i swap
0000000000000c51 W void swap<double>(double&, double&)
0000000000000c24 W void swap<int>(int&, int&)
The nm tool lists all the symbols from the input object file. The -C option decodes the low-level symbols into user level names. In our case we are listing the objects of the template_instance_swap object file and then searching the string swap in in the listing, and it shows that the compiler has generated two different versions of the template function, one for the type int and the other for the type double. The two instances of the template function are located at the memory address 0000000000000c51 and 0000000000000c24, respectively.
If you want to look further into the compiler-generated code, you can go to the online Compiler Explorer (https://godbolt.org/) and copy or upload your CPP file in the left pane of the explorer, select the appropriate compiler (for example, x86-64 gcc 10.1) and compile your code. On the right-hand pane, the output of the compilation will be displayed. If we copy-paste or upload our current program in the left pane and select the compiler as x86-64 gcc 10.1, it generates the output file as shown in the following image:

On the right-hand side pane of the explorer, look for the main() function. Under main() you will see the call to the swap() function template as shown:
call void swap<int>(int&, int&)
call void swap<double>(double&, double&)
This proves that the compiler deduced the types of arguments correctly. Further down on the right-hand pane, you will notice the instantiated definitions of the two functions as shown:
void swap<int>(int&, int&):
void swap<double>(double&, double&):
To generate the assembly code offline you can use the -S switch of the g++ compiler as the following:
$ g++ template_instance_swap.cpp -S
This will generate an output file called template_instance_swap.s as shown below:
$ ls -la template_instance_swap.s
-rw-r--r-- 1 VBR09 tpl_sky_pdd_jira_user 6280 Aug 20 14:42 template_instance_swap.s
The file template_instance_swap.s contains the assembly code generated by the compiler. You can open the file and examine the compiler generated assembly version of the template function swap(). Also, in the command line you can search for the template function name in the assembly code as the following:
$ cat template_instance_swap.s | grep -i swap
The output of this command will be cluttered with lots of assembly symbols. The most interesting are the following two lines:
_ZN11mynamespace4swapIiEEvRT_S2_:
…
_ZN11mynamespace4swapIdEEvRT_S2_:
This is how the swap() template function name looks like in the assembly code. These are called mangled names. Simply put C++ compiler modifies the function (and identifier) names so that the linker can differentiate them uniquely from other names. To generate a human-readable name from the above, you can use the following tool:
$ c++filt _ZN11mynamespace4swapIiEEvRT_S2_
void mynamespace::swap<int>(int&, int&)
$ c++filt _ZN11mynamespace4swapIdEEvRT_S2_
void mynamespace::swap<double>(double&, double&)
Now different compiler-generated versions of the swap() function can be seen in a more human-readable way. One other way you can examine the template instantiation is using the https://cppinsights.io/. This is a great resource. If you go to this site, you will see something like the following:

On the left-hand side pane, you can write your cpp code. Alternatively, you can copy the example code and paste it in the left-hand side pane as shown in the following diagram:

Once you have copied the example code and pasted it in the left-hand pane, as shown in Figure 2.6, look for the Run button on the Upper-left corner of the page (the Run button looks like the one shown in Fig. 2.6). You can also select the compiler you would like to use. For this example, I have chosen C++ 11. Once you select the Run button, you should be able to see the instantiated versions of the template function swap() on the right-hand pane, similar to the following:

As shown in Figure 2.7, the compiler has instantiated two different versions of the swap() template function, one with the int type data and the other with the double type data. This is just another way of examining what the compiler generates against our template function code. The observation is similar to what with have observed previously using other tools. So, the compiler implicitly generated two different versions of the function template in this program. However, it is also possible to explicitly direct the compiler to instantiate function template. In the next section, we will see how to do that.
Explicit instantiation
In explicit instantiation of template functions, we explicitly instruct the compiler to create an instance of the template function at that point rather than waiting for the template function to be called from somewhere. Let us see this in the following example. We will first look at the header file:
#ifndef __H_EXPLICIT_INST__
#define __H_EXPLICIT_INST__
#include <iostream>
template<typename T>
T add(T x, T y)
{
return x + y;
}
template int add<int>(int x, int y);
#endif
In the header file explicit_instantiation.h, we have defined a function template add(), then explicitly instantiated the add() function template as the following:
template int add<int>(int x, int y);
The above statement instructs the compiler to instantiate the template function with the data type int. The compiler will instantiate the template function as soon as it processes this instruction without waiting for the template function to be called from anywhere in the program. We can verify this with the help of the following verification code:
verify_explicit_instantiation.cpp
#include <iostream>
#include "explicit_instantiation.h"
int main()
{
std::cout << "Hello World" << std::endl;
return 0;
}
Notice in the verify_explicit_instantiation.cpp file we have added the header file explicit_instantiation.h but nowhere in the program have we called the template function add(). As the header file has the instruction for explicit instantiation for data type int, the compiler must create an instance even if the template function has not been called in the program. Let us compile the code and check if the add() template function has been instantiated as the following:
g++ verify_explicit_instantiation.cpp -o verify_explicit_instantiation
$ nm -C verify_explicit_instantiation | grep -i "add"
000000000000094b W int add<int>(int, int)
As you can see, the binary executable of the program verify_explicit_instantiation has an instance of the add() template function with the data type int. So, the compiler has generated binary code for the template function add() without the template function being called anywhere in the program. This is possible because of the explicit instantiation in the header file as explained. To further verify this, comment out the below statement from the explicit_instantiation.h header file:
template int add<int>(int x, int y);
And then, compile the program and search for the add() symbol using the nm tool as was shown in the following:
$ g++ verify_explicit_instantiation.cpp -o verify_explicit_instantiation
$ nm -C verify_explicit_instantiation | grep -i "add"
As you can see, there is no instance created for the add() template function as it has neither been used in the program nor been explicitly instantiated in the header file. Now that we have verified the explicit instantiation and corresponding binary code generation, let us see how the add() template function is used in a CPP file as the following:
#include<iostream>
#include "explicit_instantiation.h"
void foo();
int main()
{
std::cout << add(10, 20) << std::endl;
foo();
return 0;
}
#include "explicit_instantiation.h"
void foo()
{
std::cout << add(30, 50) << std::endl;
}
In explicit_instantiation_2.cpp we have called add() function template from the foo() function. Then in the main() function of the explicit_instantiation_1.cpp we have first we have called add() function template, and then called foo() function. Now, you can compile the program as follows:
g++ explicit_instantiation_1.cpp explicit_instantiation_2.cpp -o explicit_instantiation -Wall -Werror
The compiler compiles both the CPP files, and then the linker internally links them together and creates the final binary executable file explicit_instantion. Remember, explicit instantiation takes away the flexibility that function templates provide. However, it may be handy in some specific cases. The usage of explicit instantiation is limited, so we will not go into too many details here. It is essential to remember that explicit instantiation is possible, and if needed, this is how we can do that. In the next section, we will see how we can explicitly specify the type of instantiated function templates.
Explicitly specifying the argument types
So far, we have seen the compiler automatically deduces of the template arguments and uses the deduced types for function template instantiation. However, at times we may need to explicitly promote the type of the template argument to enforce certain operation. In the following sections, we will see how we can do that.
Explicit type conversion of template arguments
Let us say you have defined a template function to compare two numbers. It has a single template parameter of type T, and two function arguments both of type T. Now, for programing requirements, let us say you have an int and a double. You want to use the same function template and compare the int with the double. Why would you want to do that? Because you know that in this case, even if you promote the int to double and compare with another double, it will do no harm, so it is okay to do that. However, if you pass the int and the double to the template function, the compiler will throw an error during parameter checking. So how do you achieve this? Lets’ have a look at the following code snippet:
#include <iostream>
#include <typeinfo>
namespace mynamespace {
template<typename T>
T is_equal(const T& x, const T& y) {
std::cout << "type of x = " << typeid(x).name() << std::endl;
std::cout << "type of y = " << typeid(y).name() << std::endl;
return x == y;
}
}
int main()
{
int var1 = 10;
double var2 = 20.0;
if(!mynamespace::is_equal<double>(var1, var2)) {
std::cout << var1 << " " << var2 << " are not equal" << std::endl;
}
return 0;
}
In the previous program, we have a variable var1 which is of type int and var2 which is of type double. You want to compare var1 and var2 even if they are of different types. You are sure that type conversion of the var1 from int to double is okay with the current programming requirements. To do that, you can specify the intended type (in this case double) within angle brackets just after the template function as shown:
if(!mynamespace::is_equal<double>(var1, var2)) {
To prove that the compiler converts the var1 to double we have used typeid to print the types of x and y in the template function. If you compile and run the program, you will see the following:
$ g++ type_promotion.cpp -o type_promotion -Wall -Werror
$ ./type_promotion
type of x = d
type of y = d
10 20 are not equal
The typeid operator returns the run time (dynamic) type of an object (in our case var1 and var2). Notice that the types of var1 has been returned as d (double) by the typeid operator (as can be seen in the output). This proves that our intended type conversion of var1 from int to double worked. To check if the compiler generated code for the template function using type double, you can use the nm tool (we learnt before) as shown:
$ nm -C type_promotion | grep -i is_equal
0000000000000b85 W double mynamespace::is_equal<double>(double const&, double const&)
As you can see, the compiler has instantiated the is_equal() function template using the type double. There is one other situation when we might have to do explicit type specification. In the next section, we will discuss that.
Specifying argument type explicitly
Usually, the compiler is smart enough to deduce the arguments’ type from the template function call itself. However, there may be a situation where the types of the arguments are not evident from the function template call. Let’s have a look at the following example:
#include <iostream>
#include <string.h>
const int max_size = 32;
template<typename T>
T* my_alloc_factory()
{
return new T[max_size];
}
int main()
{
char *myPtr = my_alloc_factory();
strncpy(myPtr, "Hello World", max_size);
std::cout << myPtr << std::endl;
delete[] myPtr;
return 0;
}
In this example, we have defined a function template which creates an array of T type elements of size max_size in the memory and returns the allocated memory address (pointer of type T) to the caller. The template has been called from main in the following line:
char *myPtr = my_alloc_factory();
The intention here is to allocate a memory area of max_size of type char. An array of char type data is called string. Now, if you try to compile the program, you will see errors similar to following:
explicit_argument.cpp: In function 'int main()':
explicit_argument.cpp:12:36: error: no matching function for call to 'my_alloc_factory()'
explicit_argument.cpp:5:4: note: candidate: template<class T> T* my_alloc_factory()
T* my_alloc_factory()
^~~~~~~~~~~~~~~~
explicit_argument.cpp:5:4: note: template argument deduction/substitution failed:
explicit_argument.cpp:12:36: note: couldn't deduce template parameter 'T'
char *myPtr = my_alloc_factory();
The compiler is telling us that it failed to deduce the type of argument to be used for instantiation from the template function call itself. There is no argument passed to the template function call; hence the compiler could not deduce the type. To resolve this, you have to explicitly specify the type to be used for instantiation within angle brackets as shown:
char *myPtr = my_alloc_factory<char>();
As you can see, we specified the type char explicitly as shown in the previous line. This will tell the compiler that it is dealing with char type here and there will be no compilation error. In the next section we are going to learn how name of a template function can have a conflict either with the names of the template functions available in STL or with the names of any previously defined template functions in the global name space and the solution to it.
Handling function template name conflicts
If you are naming your function templates same as the ones in the STL, you may have a name conflict. Name conflict means the compiler may get confused which version of the template definition it should refer while trying to instantiate. Consider the following program:
#include <iostream>
using namespace std;
template<class T>
const T& min(const T& a, const T& b)
{
return (b < a) ? b : a;
}
int main()
{
int min_of_int = min(100, 200);
std::cout << "Min of 100 and 200 is " << min_of_int << std::endl;
return 0;
}
In this program, we have defined a min() function template and then called it in the main() function. Notice that we have brought in the std namespace in our code as:
using namespace std;
Bringing in the std namespace is to create a conflict intentionally to demonstrate the problem. I tend to avoid bringing the whole std namespace into the program as we do not need the whole std namespace. Alternatively, you should specify the scope of the symbols used from the namespace, by specifying the name of the namespace followed by scope resolution operator. Now, if you try to compile the program, the compilation will fail as shown:
g++ min_numbers_conflict.cpp -o min_numbers_conflict -Wall -Werror
min_numbers_conflict.cpp: In function 'int main()':
min_numbers_conflict.cpp:12:34: error: call of overloaded 'min(int, int)' is ambiguous
min_numbers_conflict.cpp:5:10: note: candidate: const T& min(const T&, const T&) [with T = int]
const T& min(const T& a, const T& b)
The compiler is saying that the definition of the template function min() is ambiguous. The min() function template definition in the std namespace and the one defined in this program have the same name and hence a conflict. We can resolve this issue in two ways. The first solution is to use the scope resolution operator. We will discuss how to do that in the next section.
Using scope resolution operation
To avoid the name conflict and hence the ambiguity reported by the compiler in the previous section, we can use the scope resolution operator :: as below shown in the following program:
min_numbers_scope_operator.cpp
#include <iostream>
using namespace std;
template<class T>
const T& min(const T& a, const T& b)
{
return (b < a) ? b : a;
}
int main()
{
double min_of_double = ::min(4.5, 2.3);
std::cout << "Min of 4.5 and 2.3 is " << min_of_double << std::endl;
return 0;
}
As you will notice in the previous program, the scope resolution operator is preceding the min() function call as:
double min_of_double = ::min(4.5, 2.3);
Here, the scope resolution operator directs the compiler to use the min() function template definition from the global namespace (our definition falls in the global namespace), not from the std namespace. However, this will only work if there is no other min() template function defined in the global namespace. If there is another min() template function in the global space, you have to separate your definition using a namespace. We will discuss that in the next section.
Using namespace for function templates
The problem of name conflict can be resolved by using a separate namespace for our template function. Let’s have a look at the following code snippet:
#include <iostream>
using namespace std;
namespace mynamespace {
template<class T>
const T& min(const T& a, const T& b)
{
return (b < a) ? b : a;
}
}
int main()
{
int min_of_int = mynamespace::min(100, 200);
std::cout << "Min of 100 and 200 is " << min_of_int << std::endl;
double min_of_double = std::min(4.5, 2.3);
std::cout << "Min of 4.5 and 2.3 is " << min_of_double << std::endl;
return 0;
}
In the previous program, we have defined our namespace mynamespace, and then in the main() function, we have used the scope resolution operator to specify our namespace as:
mynamespace::min(100, 200);
This will tell the compiler that the definition of the template function min() should come from the namespace mynamespace and not from the std namespace.
Whereas in the second case, we have specified the std namespace before the min() template function to tell the compiler to use the definition of min() from the std namespace:
std::min(4.5, 2.3);
The use of two different namespaces highlights that template functions may have the same name in different namespaces. Defining namespace gives us more flexibility and removes ambiguity from the code.
Summary
We started this chapter with learning about the basic syntax of function templates. Then we wrote our function template following the syntax we learned. Then we moved on to understanding how the compiler compiles the template function in two phases. The first phase only checks the syntactic correctness and the symbols used in the template definition. If there is any syntactical error or encounters an unknown symbol, the compiler throws an error. In the next phase, when the function template is called with arguments, the compiler performs a type check and checks the overall code’s validity.
We learned about the function template instantiation and looked into the compiler-generated code to check what the compiler generates for our function templates’ definition. We then discussed how to promote the types of function arguments explicitly. We also examined how to tell the compiler which type to use for function template instantiation if it is not evident from the function template call. Finally, we saw how we could separate our function template definition from the standard template library definition.
Learning how the function templates work and how to write custom function templates is a big step toward learning about C++ templates. Most of the things discussed in this chapter apply to class templates as well. So, if you have grasped the concepts discussed in this chapter well, you have given yourself a perfect foundation for the upcoming chapters and well-footed yourself towards the overall learning pathway. In the next chapter, we will learn more about different types of function template parameters and arguments.
Questions
- What are the keyword used to declare and define a template function?
- What is the keyword that we can use instead of typename while defining a template function in C++?
- The keyword class in a template function definition/declaration indicates a user defined class for data encapsulation. (True/False).
- In how many phases the compiler processes the template function?
- Logical errors in the function template body may not be detected by the compiler if the template function has not been called anywhere in the program. (True/False).
- Only Syntactical errors and unknown symbols are checked in the first phase of compilation of the template function. (True/False)
- In implicit instantiation the compiler detects the type of the template function arguments automatically from the template function call. (True/False)
- Scope resolution operator can be used to tell the compiler that the template function name comes from the global namespace. (True/False)
- What is the keyword we need to use to define a custom namespace in C++?
- When we call a template function the compiler create a new instance of the template function with the real type even if the instance has been created before. (True/False)
Answers
- template and typename
- class
- False. Keyword class in template function definition only denotes a type parameter. Instead of class, we can also use typename to avoid any confusion.
- Two phases
- True
- True
- True
- True
- namespace
- False. If a template function has been instantiated with a particular set of data types, then no further instance will be created by the compiler.
Leave a Reply