Generic Programming in C++
Overview
The templates in C++ are used to write the data type independent piece of code. The specified placeholder in the code gets replaced by the actual data type at the time of compilation, called the instantiation of code. The class or function written as the template is called Generics, and this entire concept is called Generic Programming in C++.
Introduction to Generic Programming in C++
The generic programming pattern generalizes the algorithm with the help of templates in C++ so that it can be used along with different data types. In templates, we specify a placeholder instead of the actual data type, and that placeholder gets replaced with the data type used during the compilation. So, if the template function were being called for integer, character, and float, the compiler would produce 3 copies of the function. This is possible because of the static-type nature of C++.
Use of Templates
To understand the use of templates, let's briefly discuss normal programming. In the C++ programming language, all data must be stored in a container. Technically, these are termed as data types like int, float, user-defined, etc.
As we know, the algorithm could be the same for different types of data, i.e., the procedure to find the distance between two coordinates will remain the same irrespective of whether the coordinates are given as integer or floating-point numbers. But in C++ Programming, we must write different functions for both data types because the int data type is incapable of storing float values, and using the float data type for int values is a waste of memory. So, Templates in C++ solve this problem by providing a generalized algorithm.
Function Template
The function templates are used to write functions with generic types that can adapt functionality according to the data type used during the function call. This makes us easier to perform the same operation on different data types without code replication.
Example: Finding Maximum of two Numbers
Output:
Note: In the above example, we have specified the data type with the function call itself, but this could be skipped as the compiler automatically detects the values we give to the function.
Guidelines for Using Template Functions
This section will discuss Syntax, general guidelines, and a few important things related to template functions.
Generic Data Types
Generic types are classes or functions that are parameterized over a type. This is done with templates in C++. The template parameters are used to create a generic data type. This concept is similar to function parameters, we pass some template arguments, and the function receives it as a type value.
The syntax to specify the template parameters is,
Either we use the class keyword or typename. Both approaches are the same.
Declaration and Definition Must Be in the Same File
The templates are not normal functions. They only get compiled when some instantiation with particular template arguments. The compiler generates the exact functionality with the provided arguments and template. Because templates are compiled when required, it is impossible to separate the definition and declaration of the template functions into two files.
Overloading Function Templates
The template functions can be overloaded. The compiler will search for the exact overloaded function definition if any particular function call is encountered inside the program. If found, then the overloaded function will execute. Otherwise, the matched template function will execute. Further, if no template function is associated with the function call, the compiler will throw an error.
Output:
Explanation:
- For the first function, call sum(4.5,9.8); the compiler will search for the exact function that doesn't exist and then search for the template function, as the template exists, so that it will be executed.
- For another function call, sum(5,7); there already exists an overload function for the exact data type. Hence template function will not be called.
Recursive Template Functions
The recursion can be achieved with the template functions, and from the program execution's point of view, everything works the same as the normal recursive function.
Function Templates with User Defined Types
We are free to choose any type that we are going to pass inside the template parameters of the function template. The inference is that we can also create function templates with user-defined types.
Output:
Explanation:
- We have created a user-defined type as Person, which has a toString method and constructor along with some private entities.
- Subsequently, there is a function template to print the data by calling that function with the corresponding user-defined data type.
- When the compiler parses the call printTheData(p1); a copy of the template function with the specific data type will be created, and this call will be calling that copy of the template function where Person replaces T.
Class Template
Like function templates, we can also use templates with the class to make it compatible with more than one data type. In C++ programming, you might have used the vector to create a dynamic array, and you can notice that it works fine with every data type you pass inside the <>, ex- vector<int>. This is just because of the class template.
Syntax:
Class Template and Friend Functions
A non-member function that is defined outside the class and can access the private and protected members of the class is called a friend function. These are used to create a link between classes and functions. We can define our friend function as a template or a normal function in the class template.
Class Templates and Static Variables
The classes in C++ can contain two types of variables, static and non-static(instance). Each object of the class consists of non-static variables. But the static variable remains the same for each object means it is shared among all the created objects. As we are discussing the templates in C++, a point worth noticing is that the static variable in template classes remains shared among all objects of the same type.
Output:
Explanation:
- We have created a template class named Container which contains static member count.
- We could see from the above example that for different data types, static variables have different values, which shows every type has a separate copy of the static variable.
Class Template and Inheritance
Concepts of inheritance work in a similar way for class templates also. There could be a few major scenarios in Class Template Inheritance which are listed below.
1. Base Class is not a Template class, but a Derived class is a Template class. We can derive from the non-template class and add template members to the derived class.
2. Base Class is a Template class, but Derived class is not a Template class. We can derive from a template class. If we don't want our derived class to be generic, we can use the Base class by providing the template parameter type.
3. Base Class is a Template class, and the Derived class is also a Template class. If we want our derived class to be generic, then it should be a template that can pass the template parameter to the base class.
Here Base Class and Derived Class are using the same Type.
4. Base Class is a Template Class, and derived class is a Template class with different Types.
We can also use more types in the derived class by including them in the template parameter of the derived class template.
Templates vs. Macros
The templates and macros are somewhat similar; the table below demonstrates the few differences between them.
Templates | Macros |
---|---|
Templates are the special function or classes with generic types. | Macros are the segment of code that is replaced by the macro value. They are defined by #define directive. |
Templates get instantiated by the compiler only if a function call exists. | The preprocessor resolves macros during the first phase of compilation, i.e., preprocessing. |
Easy to debug, because at the end template is just a function | Little bit complex to debug because the preprocessor handles everything. Also, while working with macros, you can notice that the error for macros is being shown up at the line where macro is defined. |
Template is an advanced form of substitution. | Macro is a primitive form of substitution. |
Templates are nothing but function calls, hence less efficient as compared to macros. | The macros are efficient because of inline compilation |
Templates go through type-checking during compilation. | There is no type checking in macros. |
Advantages and Disadvantages of Templates
Advantages
1. Code Compaction, By using templates, we can define generalized functionality and eliminate the repetition of several algorithms for different data types.
2. Reusability of Code, We can define a template that can be used with multiple data types.
3. In-Demand Compilation, One of the amazing advantages of using the template is that when the compiler encounters any function call with associated data types, only the new function is instantiated from the template.
Disadvantages
1. Data Hiding issue, Since the declaration and definition of the template cannot be separated due to in-demand compilation, it is difficult to hide functionality written inside the template.
2. Lack of Portability, Not every compiler supports the templates; hence in rare cases, there might be some portability issues.
Bubble Sort Using Function Template
Below is the implementation of bubble sort with the function template.
Output:
Explanation:
- We have defined a function template for bubble sort, which has template parameter T.
- As soon as we call the bubbleSort function for arr1, the compiler will instantiate a bubbleSort function for the int data type and use it for that function call.
- Similarly, this template will work with every data type, i.e., char, int, float, etc.
Linked List Using Class Template
Below shown is the template for a linked list. There are two private members, as usual, and three public methods, namely,
- printList: To print the entire list
- pushFront: To push the data into the front of the linked list.
- deleteFront: To delete the data from the front of the linked list.
Let's see how we can utilize it for different data types,
1. List of Strings
Output:
2. List of Integers
Output:
As shown in the above example, we could use the same list class template for string data type, integer data type, and even for any other data type.
Conclusion
- The templates in C++ generalize the algorithm to make it data type-independent. The functions and classes which are data type independent are called generics, and this concept is called generic programming.
- Generic Programming reduces code repetition and in-demand compilation; hence efficient.
- In the function template few points worth noticing are,
- The overloading is possible; an overloaded function will be called first if it exists.
- The recursion technique works similarly also in the function templates.
- The declaration and definition of the template must be in the same file.
- In the class template few points worth noticing are,
- We can use the friend function in a class template as well.
- Each type of class contains a separate copy of static variables.