Templates in C++

Why Template?

#include <iostream>

class comprehendTemplate {
  private:
        int val;
  public:
        comprehendTemplate(int num) : val(num) { 
                std::cout << "val " << val;
        }
};

int main()
{
    comprehendTemplate ct(9);
    comprehendTemplate ct2("Hello");

    return 0;
}

Output:

1
2
3
<source>: In function 'int main()':
<source>:15:28: error: invalid conversion from 'const char*' to 'int' [-fpermissive]
   15 |     comprehendTemplate ct2("Hello");
      |                            ^~~~~~~
      |                            |
      |                            const char*
<source>:7:32: note:   initializing argument 1 of 'comprehendTemplate::comprehendTemplate(int)'
    7 |         comprehendTemplate(int num) : val(num) {
      |                            ~~~~^~~
ASM generation compiler returned: 1
<source>: In function 'int main()':
<source>:15:28: error: invalid conversion from 'const char*' to 'int' [-fpermissive]
   15 |     comprehendTemplate ct2("Hello");
      |                            ^~~~~~~
      |                            |
      |                            const char*
<source>:7:32: note:   initializing argument 1 of 'comprehendTemplate::comprehendTemplate(int)'
    7 |         comprehendTemplate(int num) : val(num) {
      |                            ~~~~^~~
Execution build compiler returned: 1

Click here to debug the above program.

Template

Class template is a class written with the generic programming paradigm, specifying behavior in terms of type parameter rather than specific type.

Function templates are special functions that can operate with generic types. This allows us to create a function template whose functionality can be adapted to more than one type or class without repeating the entire code for each type.

template <typename identifier> function_declaration;

template <class identifier> function_declaration;

Both have the same meaning and are indistinct. 

A variable template is therefore a template that defines a series of variables, based on one or more template parameters: (C++14 feature)

template<typename T>                            
T variable_name{};                                   





Now let's try to create general programming paradigm. 

Template for class

#include <iostream>

template <class T>
class comprehendTemplate {
  private:
        T val;
  public:
        comprehendTemplate(T num) : val(num) { 
                std::cout << "val " << val;
        }
};

int main()
{
    comprehendTemplate ct(9);
    comprehendTemplate ct2("Hello");

    return 0;
}

Output:

1
2
3
In function 'int main()':
Line 15: error: missing template arguments before 'ct'
compilation terminated due to -Wfatal-errors.

In this case, we have used T as the template parameter name it is shorter and in fact is a very common template parameter name. But you can use any identifier you like.

The above class comprehendTemplate is template class, so to create object for this we need to use the following format.

class-name <type>object-name(<parameters if any>);

Still our C++ compilers are not intelligent to detect the type automatically. 

Template for constructors

#include <iostream>

template <class T>
class comprehendTemplate {
  private:
        T val;
  public:
        comprehendTemplate(T num) : val(num) { 
                std::cout << "val " << val << std::endl;
        }
};

int main()
{
    comprehendTemplate <int>ct(9);
    comprehendTemplate <std::string>ct2("Hello");

    return 0;
}

Output:

1
2
val 9
val Hello

When the compiler encounters this call to a template function, it uses the template to automatically generate a function replacing each appearance of 'T' by the type passed as the actual template parameter (int in this case) and then calls it. This process is automatically performed by the compiler and is invisible to the programmer.

The template can also be used for member functions & free functions.

Template for Member functions

#include <iostream>

template <class T>
class comprehendTemplate {
  private:
        T val;
  public:
        comprehendTemplate(T num) : val(num) { 
                std::cout << "val " << val << std::endl;
        }
        
        T getVal() { return val; };
};

int main()
{
    comprehendTemplate <int>ct(9);
    comprehendTemplate <std::string>ct2("Hello");
    std::cout << "getVal of ct " << ct.getVal() << std::endl;
    std::cout << "getVal of ct2 " << ct2.getVal() << std::endl;
    
    return 0;
}

Output:
1
2
3
4
val 9
val Hello
getVal of ct 9
getVal of ct2 Hello

Template for Member function & constructor defined outside class 

#include <iostream>

template <class T>
class comprehendTemplate {
  private:
        T val;
  public:
        comprehendTemplate(T num);
        
        T getVal();
};

comprehendTemplate::comprehendTemplate(T num) : 
        val(num) { 
        std::cout << "val " << val << std::endl;
}

T comprehendTemplate::getVal() 
{
   return val;
}

int main()
{
    comprehendTemplate <int>ct(9);
    comprehendTemplate <std::string>ct2("Hello");
    std::cout << "getVal of ct " << ct.getVal() << std::endl;
    std::cout << "getVal of ct2 " << ct2.getVal() << std::endl;
    
    return 0;
}

Output:
1
2
Line 13: error: 'template<class T> class comprehendTemplate' used without template parameters
compilation terminated due to -Wfatal-errors.

When we want to define the constructors and member functions outside the class, the complier couldn't interpret the type passed. So, we need to pass the template parameter for compiler to understand. 

#include <iostream>

template <class T>
class comprehendTemplate {
  private:
        T val;
  public:
        comprehendTemplate(T num);
        
        T getVal();
};

template <class T>
comprehendTemplate<T>::comprehendTemplate(T num) : 
        val(num) { 
        std::cout << "val " << val << std::endl;
}

template <class T>
T comprehendTemplate<T>::getVal() 
{
   return val;
}

int main()
{
    comprehendTemplate <int>ct(9);
    comprehendTemplate <std::string>ct2("Hello");
    std::cout << "getVal of ct " << ct.getVal() << std::endl;
    std::cout << "getVal of ct2 " << ct2.getVal() << std::endl;
    
    return 0;
}

Output:
1
2
3
4
val 9
val Hello
getVal of ct 9
getVal of ct2 Hello


As we need to repeat the template syntax in all the definitions, we usually define all the functions inside the class if it is a template class.

Template for Copy Constructor & Assignment Operator

#include <iostream>

template <class T>
class comprehendTemplate {
  private:
        T val;
  public:
        comprehendTemplate(T num):val(num) { 
           std::cout << "Parameterised Constructor" << std::endl; 
           std::cout << "val " << val << std::endl; 
        }
        
        comprehendTemplate(const comprehendTemplate& other) { 
                std::cout << "Copy Constructor" << std::endl; 
                val = other.val;
        }
        
        comprehendTemplate& operator=(const comprehendTemplate& other) { 
                if (this != &other) {
                    std::cout << "Assignment Operator Constructor" << std::endl;
                    val = other.val;
                }
                return *this;
        }
        
        T getVal(){
           return val;
        }
};

int main()
{
    comprehendTemplate <int>ct(9);
    comprehendTemplate <std::string>ct2("Hello");
    std::cout << "getVal of ct " << ct.getVal() << std::endl;
    std::cout << "getVal of ct2 " << ct2.getVal() << std::endl;
    
    comprehendTemplate <std::string>ct3 = ct2;
    std::cout << "ct3 is a copy of ct2 " << ct3.getVal() << std::endl;
    comprehendTemplate <int>ct4(10);
    std::cout << "getVal of ct4 " << ct4.getVal() << std::endl;
    ct4 = ct;
    std::cout << "ct4 replaces the data with ct " << ct4.getVal() << std::endl;
    
    return 0;
}


Output:
1
2
3
4
5
6
7
8
9
10
11
12
13
Parameterised Constructor
val 9
Parameterised Constructor
val Hello
getVal of ct 9
getVal of ct2 Hello
Copy Constructor
ct3 is a copy of ct2 Hello
Parameterised Constructor
val 10
getVal of ct4 10
Assignment Operator Constructor
ct4 replaces the data with ct 9

Click here to debug the above program.

Template for pointer member variables

I've a variable with pointer, and now I want the below program to accept all types.
#include <iostream>

class comprehendTemplate {
  private:
        int* val;
  public:
        comprehendTemplate(int num) : val(new int(num)) { 
                std::cout << "val " << val << std::endl;
        }
        
        int getVal() { 
            int num = *val;
            return num; 
        };
};

int main()
{
    comprehendTemplate ct(9);
    std::cout << "getVal of ct " << ct.getVal() << std::endl;
    
    return 0;
}
Output:
1
2
val 0x891f438
getVal of ct 9


I just converted this to accept any data type but not the string. 

#include <iostream>

template <class T>
class comprehendTemplate {
  private:
        T* val;
  public:
        comprehendTemplate(T* num):val(new T) { 
           std::cout << "Parameterised Constructor" << std::endl;
           val = num;
           std::cout << "val " << *val << std::endl; 
        }
        
        
        comprehendTemplate(const comprehendTemplate& other) { 
                std::cout << "Copy Constructor" << std::endl; 
                val = other.val;
        }
        
        comprehendTemplate& operator=(const comprehendTemplate& other) { 
                if (this != &other) {
                    std::cout << "Assignment Operator Constructor" << std::endl;
                    val = other.val;
                }
                return *this;
        } 
        
        T* getVal(){
           return val;
        }
        
};

int main()
{
    int var = 9;
    comprehendTemplate <int>ct(&var);
    //comprehendTemplate <std::string>ct2("Hello");
    std::cout << "getVal of ct " << ct.getVal()  
              << " " << *(ct.getVal()) << std::endl;
    //std::cout << "getVal of ct2 " << ct2.getVal() << std::endl;
    
    
    comprehendTemplate <int>ct3 = ct;
    std::cout << "ct3 is a copy of ct " << ct3.getVal() << std::endl;
    //var = 10;
    int var2 = 10;
    comprehendTemplate <int>ct4(&var2);
    std::cout << "getVal of ct4 " << ct4.getVal() 
              << " " << *(ct4.getVal()) << std::endl;
    ct4 = ct;
    std::cout << "ct4 replaces the data with ct " << ct4.getVal() << std::endl;
    
    return 0;
}

Output:
1
2
3
4
5
6
7
8
9
10
Parameterised Constructor
val 9
getVal of ct 0xffc28634 9
Copy Constructor
ct3 is a copy of ct 0xffc28634
Parameterised Constructor
val 10
getVal of ct4 0xffc28630 10
Assignment Operator Constructor
ct4 replaces the data with ct 0xffc28634

Click here to debug.

Stack Implementation is the good example of class template. 

Template for Arrays

To be updated.

Template for two classes




Template for free functions

#include <iostream>
using namespace std;

// One function works for all data types.
// This would work even for user defined types
// if operator '>' is overloaded
template <typename T>

T myMax(T x, T y)
{
	return (x > y) ? x : y;
}

int main()
{

	// Call myMax for int
	cout << myMax<int>(3, 7) << endl;

	// call myMax for double
	cout << myMax<double>(3.0, 7.0) << endl;

	// call myMax for char
	cout << myMax<char>('g', 'e') << endl;

	return 0;
}

Output:
1
2
3
7
7
g

Generics

Generics can be implemented using C++ templates. 


Advantages 

Template generally deduces the size from the variable passed which is called template parameter deduction. 

The advantages of Generic Programming are
1) Code Reusability
2) Avoid Function Overloading
3) Once written it can be used for multiple times and cases.

References

Class with classname given as a template argument

Class with same members but different class Name

CPPReference Template

Comments