Thursday, January 14, 2010

Templates


Custom Search


Wow... a new dimension in C++ coding ... Templates have taken re-usability to a new level , it is the reuse of source code. Yes that's what Template is all about, generic source code developement. Well you already must be knowing the basics , but just for the sake of completeness we will them and move on.

Defining a function template:
template<class T>
void swap(T &a , T &b)
{
   T tmp = a;
   a = b;
   b = tmp;
}

Using a template function:
 Its simple just call like a normal function.... 

int main()
{
  int a =10, b = 20;
  swap( a,b);
   ......
  char x = 'a' , y = 'b';
  swap(x,y);
  .....
}

Note the underlined terms used with respect to the context, in the above headings.

Defining Class Templates
templates<class T>
class X
{
private:
   T data;
public:
 X(T a)
{
   data = a;
}

T getData();
..... 
};

//defining the class template method
template<class T>
T  X<T>::getData()
{
  return data;
}

Using the template class

int main()
{
.....
 X<int> obj(10);
....
int a = obj.getData();
....
}.

As templates are not normal functions or classes they are not compiled until required(on instantiation with the appropriate arguments) we cannot separate the interface and the implementation into two (.h & .cpp)  files, they must be in the same file.



Template Instantiation

Template instantiation can be of two types Implicit(the compiler generates the code by itself because of the instantiation) and Explicit(the programmer tells the compiler to generate  the code). See the below examples:

// Consider the class template
template<class T>
class X
{
 private:
     T  data;
public:
    T getData();  // member function that uses the template type(here T).
};

// case 1
int main()
{
   X<int> xi;          //implicit instantiation generates class X<int>
   X<double> xd;  //implicit instantiation generates class X<double>
   xi.getData();               //generates function X<int>::getData()
   xd.getData();             //generates function X<double>::getData()
   return 0;

}


//case 2

int main()
{
   template class X<int>  // explicit instantiation of class X<int> , no object declared.

   return 0;
}

//case3
// This time the compiler does not declare any definition because there is no need.
// Its the same as declaring a pointer to an undefined class.
int main()
{
   X<int>  *p_xi;          //instantiation of class X<int> not required.
   return 0;
}

//case 4
// Implicit instantiation function template
template<class T>
T max(T a, T b)
{
  return (a>b)? a: b;
}

int main()
{
 int i;
 i  = max(10, 20) ;   // implicit instantiation of max(int ,int)
 return 0;
}

// case 5
// explicit instantiation of function templates.

template<class T>
T fun(T a)
{
 ....
}

int  main()
{
   template  int fun (int);  // explicit instantiation
    ... 
   return 0;

}

In an extern declaration of a template the compiler does not instantiate a class template or a function template.

The typename keyword
The type name keyword tells the compiler to interpret a particular name as a type.
Have a look at the below example:

#include <iostream>

using namespace std;

class Y
{
public:
 class ID
 {
     public:
      void g()
      {
          cout << "In Y::ID::g()" << endl;
      }
 };
};

template<class T>
class X
{
    typename T::ID id;  // if we did not use the typename keyword the compiler would have given an error.
    public:
    void fun()
    {
     id.g();
    }
};


int main()
{
    X<Y> xy; 
    xy.fun();
    return 0;


In the template definition we are making two assumptions , first that inside the class T there is an identifier 'ID' and second the identifier 'ID' is actually a nested type inside T. So while compiling X the compiler will not know that 'ID' is a type and we need to convey that to the compiler. We use the typename keyword to tell the compiler that 'ID' is a type ,  if we don't say that the compiler will give an error. So here is  a simple rule that if your type is a qualified name that involves a template argument the you must use the typename keyword.


With the introduction of the typename keyword you can use it in place of  class while declaring template argument list of a template definition.


Templates and multiple file implementation:

The code for a specific template is not generated by the compiler until an instantiation takes place. Because templates are compiled when required , this forces a restriction for multi-file implementation of templates, so the implementation of a template class or function must be in the same file. 


An interesting program: A template class to find the factorial of a number.

template<long N>


class Factorial
{
    public:
    long Value()
    { 
        return N * fn_1.Value();
    }
    
    private:
    Factorial<N-1> fn_1;
};


// Specilized for the value 0
template<>
class Factorial<0>
{
    public:
    long Value()
    {
      return 1;
     }
};


int main()
{
     Factorial<20> f20;
     cout << f20.Value() << endl;
}

No comments:

Post a Comment

Followers

About Me