Templates
A template is a parameterised function for creating a generic class or function. Using templates means one function or class can be used with several different data types, without recoding specific versions for each data type. A function template starts with the keyword template followed by the template parameter(s) enclosed in angled brackets followed by the function declaration. The general form of a template function definition is −
template <class T>
T someFunction(T arg)
{
}
The generic parameter name can then be substituted for the normal variable type within the preceding function. The compiler will then generate different versions of that function corresponding to the data type within the function call
The following worked example uses a function template to return the maximum of two different values using 3 different value parameter types −
#include <iostream> #include <string> using namespace std; //creates template with parameter type myTemplate template <typename myTemplate> //template function accepts two parameter types a and b myTemplate Max (myTemplate a, myTemplate b) { if (a>b) { return a; } return b; } int main () { int i = 20; int j = 10; //calls template function and generates compile time function for int values cout << "Max(i, j): " << Max(i, j) << endl; double f1 = 13.5; double f2 = 20.7; //calls template function and generates compile time function for double values cout << "Max(f1, f2): " << Max(f1, f2) << endl; string s1 = "a"; string s2 = "b"; //calls template function and generates compile time function for char values cout << "Max(s1, s2): " << Max(s1, s2) << endl; return 0; }
A Function with Multiple Generic Types
A comma-separated list can define more than one generic data type in the template statement. The following worked example accepts two template parameter types and calls the template function using a char and int parameter followed by an int and char parameter.
#include <iostream> using namespace std; //creates template with 2 different parameter types template <class type1, class type2> void myfunc(type1 x, type2 y) { cout << x << ' ' << y << '\n'; } int main() { //calls template function with parameter types char and int myfunc("5x2=", 10); //calls template function with parameter types int and char myfunc(10, "=9+1"); return 0; }
Declaring Templates with Default Parameters
Mixing standard parameters with generic type parameters in a template function is possible. In the following worked example a template function, functionX accepts a template parameter and a standard parameter. The standard parameter is set with a default value of 0. The function is first called by specifying only the template parameter type and then called by specifying the template parameter type and standard parameter.
#include <iostream> using namespace std; template <typename X> //creates template function with template parameter and standard parameter with default value 0 void FunctionX(X value1,int value2=0) { if (value2!=NULL) { cout << value1 << " "; cout << value2 ; } else { cout << "float value=" << value1 << endl; } } int main() { float b=4.33; // calls template function using only template parameter. FunctionX(b); // calls template function using template parameter and standard parameter. FunctionX( "float value cast to int =",b); return 0; }
To set a default template parameter type in the above code using the following template declaration-
template <typename x=int>
Overloading a Generic Function
Template functions can be overloaded. In the following example, the template function T is overloaded with a function that accepts int parameter values. When the function is called with int values the overloaded function is called. All other parameter values invoke the genetic template function.
#include <iostream> using namespace std; template <class X> void T(X a, X b) { cout << "Inside template T.\n"; cout << a << b; cout << endl; } // This overrides the generic version of t for ints. void T(int &a, int &b) { cout << "Inside overloaded function\n"; cout << a << "X" << b <<"=" << a*b; } int main() { int i=10, j=20; char *word1="hello "; char *word2="word "; T(word1, word2); // calls generic template t() T(i, j); // calls overloaded function t() return 0; }
Variadic functions
Variadic functions can be used to write functions that accept an arbitrary number of arguments. Variable templates or variadic templates have been part of C++ since C++14, released in 2014
#include <iostream> using namespace std; template <typename T> double sum(T t) { //base case return t; } template <typename T,typename... Rest>//recursive case double sum(T t,Rest... rest) { return t + sum(rest...); } int main() { double dTotal = 0; dTotal=sum (33, 3.14, 4.56, 1.1111,44,55); cout << "dResult = " << dTotal << endl; return 0; }
The variadic function requires a ‘base’ case and a ‘recursive’ case. In the above example, the compiler finds and executes the sum function for each argument in turn and then executes the base function i.e. the function with no argument. The declaration of a variadic function uses ellipsis as the last parameter. The sizeof...() is an operator that can return the number of template arguments passed in a call to a variable template. In the above code cout<< sizeof...(rest) would return the number of calls left after each iteration. Programmers using variable templates can avoid the repetitive effort of creating code thus making a program shorter and simpler to maintain.
Class Template
It is also possible to write classes that utilise templates. A class template will have members that use template parameters as types. In the example below, the class template is instantiated with an int and a char, and the maximum value is returned.
// class templates #include <iostream> using namespace std; template <class T> class compare { T x, y;//declare template class variables public: compare (T firstp, T secondp) {x=firstp; y=secondp;}//set initial value of class variables T getmax (); }; template <class T> T compare<T>::getmax () { T retval; retval = x>y? x : y;//return highest class variable return retval; } int main () { compare <int> templateobject (10, 22);//instantiate class template cout << templateobject.getmax(); compare <char> templateobjectc ('e', 'z');//instantiate class template cout << templateobjectc.getmax(); return 0; }