Templates in C++

An introduction to using template classes in C++, that starts extremely simply and builds up from there…

Example 1

Consider the following simple class that we use to store and print an integer:

#include <iostream>

class A
{
private:
    int data;

public:
    A( const int& d );
    int Value() const;
    void Print() const;
};

A::A( const int& d )
{
    data = d;
}

int A::Value() const
{an
    return data;
}

void A::Print() const
{
    std::cout << data << std::endl;
}

int main()
{
    A a( 5 );
    a.Print();
}

Now suppose we wish to do this in a generic way, allowing us to store and print not only integers, but any kind of primitive data type. The equivalent template class for class A would now look like this:

#include <iostream>

template< class T>
class A
{
private:
    T data;

public:
    A( const T& d );
    T& Value() const;
    void Print() const;
};

template<class T>
A<T>::A( const T& d )
{
    data = d;
}

template<class T>
T& A<T>::Value() const
{
    return data;
}

template<class T>
void A<T>::Print() const
{
    std::cout << data << std::endl;
}

int main()
{
    A<int> a( 5 );
    a.Print();

    return 0;
}

Example 2

In this example class A is used to maintain a std::vector of generic data types, with functions to add to the vector set and print their contents:

#include <iostream>
#include <vector>#include 
#include 

template 
class Queue
{
private:
    std::vector data;
public:
    void push(T const &);
    void pop();
    T front() const;
    void Print();
};

template  
void Queue ::push(T const &d)
{
     data.push_back(d);
}

template  
void Queue::pop()
{
     data.erase(data.begin( ) + 0,data.begin( ) + 1);
}

template  
T Queue::front() const
{
    if ( data.size() > 0 ) 
    {
        return *(data.begin());
    }
    else
    {
        std::cerr << "Empty Queue. Returning garbage value\n";
        T* temp = new(T); 
        T garbage = * temp;
        delete temp; 
        return garbage;
    }
}

template  
void Queue::Print()
{
    for ( int i = 0; i < (int) data.size(); i++ )  
    {  
        T val = *( data.begin() + i );  
        std::cout << val << std::endl;      
    }  
}

int main()
{
     Queue q;         
     q.push(1);
     q.push(2);
     std::cout << q.front() << std::endl;
     std::cout << "Before removing data" << std::endl;
     q.Print();

     q.pop();
     std::cout << "After removing data"<< std::endl;
     q.Print();
     return 0;
}
#include <string>

template< class T>
class A
{
private:
    std::vector<T> v;    

public:
    void Add( const T& d );
    T& Value(const int& index) const;
    void Print() const;
};

template<class T>
void A<T>::Add( const T& d )
{
    v.push_back(d);
}

template<class T>
T& A<T>::Value(const int& index) const
{
    T val = 0;
    if (index < v.size() )
    {
        val = v[ index ];
    }
    return val;
}

template<class T>
void A<T>::Print() const
{
    for ( int i = 0; i < (int) v.size(); i++ )
    {
        T val = *( v.begin() + i );
        std::cout << val << std::endl;    
    }
}

int main()
{
    A<int>* a1 = new A<int>();
    a1->Add( 4 );
    a1->Add( 5 );
    a1->Print();
    delete a1;

    A<std::string> a2;
    a2.Add( "Hello" );
    a2.Add( "World" );
    a2.Print();
   
    return 0;
}

Example 3

This example uses a template function for finding the maximum of two generic data types:

#include <ostream>
#include <vector>
#include <string>

const int& Max( const int& a, const int& b )
{
    return a > b ? a : b;
}

template<class T>
inline const T& Max1( const T& a, const T& b )
{
    return a > b ? a : b;
}

int main()
{
    int max = Max( 5, 55 ); 
    std::cout << max << std::endl;

    double maxd = Max1( 23.3, 101.23 );
    std::cout << maxd << std::endl;

    float maxf = Max1( 23.2, 111.1 );
    std::cout << maxf << std::endl;
    return 0;
}

Example 4

An example of using template classes in a queue, to store generic data types:

#include <iostream>
#include <vector>

template <class T>
class Queue
{
private:
    std::vector<T> data;
public:
    void push(T const &);
    void pop();
    T front() const;
    void Print();
};

template <typename T> 
void Queue<T> ::push(T const &d)
{
     data.push_back(d);
}

template <typename T> 
void Queue<T>::pop()
{
     data.erase(data.begin( ) + 0,data.begin( ) + 1);
}

template <typename T> 
T Queue<T>::front() const
{
    if ( data.size() > 0 ) 
    {
        return *(data.begin());
    }
    else
    {
        std::cerr << "Empty Queue. Returning garbage value\n";
        T* temp = new(T); 
        T garbage = * temp;
        delete temp; 
        return garbage;
    }
}

template <typename T> 
void Queue<T>::Print()
{
    for ( int i = 0; i < (int) data.size(); i++ )  
    {  
        T val = *( data.begin() + i );  
        std::cout << val << std::endl;      
    }  
}

int main()
{
     Queue<int> q;         
     q.push(1);
     q.push(2);
     std::cout << q.front() << std::endl;
     std::cout << "Before removing data" << std::endl;
     q.Print();

     q.pop();
     std::cout << "After removing data"<< std::endl;
     q.Print();
     return 0;
}