In C++, templates allow us to write code that works with different data types without duplicating the same logic. A template defines a general form of a function (or classes or variables), and the compiler automatically generates the specific versions when the function is used.
Suppose we want to write a function that finds the maximum of two values. Without templates, we would need to write separate functions for each data type that we want to work with:
int myMax(int a, int b) {
return (a > b) ? a : b;
}
double myMax(double a, double b) {
return (a > b) ? a : b;
}
Other than the return types and parameter types, the logic inside the functions is identical. Writing the same code multiple times violates the DRY (Donβt Repeat Yourself) principle. To avoid this repetition, we can use templates:
template <typename T>
T myMax(T a, T b) {
return (a > b) ? a : b;
}
Before the function prototype is the template declaration. It specifies that the following function is a template function and can operate on different data types. It also specifies the type parameter T, which will be replaced with the actual data type when the function is called. You can think of <typename T> as saying βthis template works with any one data type that we will refer to as Tβ.
Then in the function definition itself, we use T as the type for the parameters and the return value. This says βwhatever type T is, use that as the return type and parameter typesβ.
When we call the function, the compiler automatically generates the appropriate version based on the argument types. For example, if we call myMax(3, 5), the compiler creates a version of myMax where T is int. If we call myMax(3.5, 2.1), it creates a version where T is double .
In this code sample, the templated version of myMax will be used to generate three different concrete versions of the code, one each for int, double, and char:
Templates are not compiled directly. They are a blueprint for generating code. When you use templated code, the compiler uses that blueprint to create the specific versions needed for the types you use.
If the compiler canβt determine what type T is supposed to be, it will result in a compilation error. For example, if we try to call myMax with an int and a double, the compiler wonβt know if it should use int or double for T:
To resolve this ambiguity, we can explicitly specify the type when calling the function by placing <TYPENAME> after the function name. When we do this, the compiler knows exactly which type to use for T. It will try to convert any other types will be converted to the specified type: