In the previous blog post we tried to write templates for median and average. Here is the code for that.


template<class T>
T median(T arr[], int num)
{
    int i, mid;
    T ret_val = T();
    shell_sort(arr,num);
    if(num%2 == 0)
    {
       mid = floor(num/2);
       ret_val = arr[mid-1] + arr[mid];
       ret_val /= 2;
    }
    else
    {
       ret_val = arr[(num/2)];
    }
    return ret_val;
}

Code block for average template is


template<typename T>
double average(T arr[], int num)
{
                double avg = 0;
                int i;
                for(i=0;i<num;i++)
                  avg += arr[i];
                avg /= num;
                return avg;
}

Client code using these templates


int main(void)
{
    int array_i[6]={44,45,32,36,16, 47}, val;
    double i_avg, f_avg, c_avg;
    val = median(array_i,6);
    i_avg = average(array_i,6);
    cout<<"\n median "<<val<<" Avg "<<i_avg<<"\n";
    float array_f[5] = {11.3f, 34.4f, 3.0f,2.3f, 4.3f}, valf;
    valf = median(array_f,5);
    f_avg = average(array_f,5);
    cout<<"\n median "<<valf<<" Avg "<<f_avg<<"\n";
    char array_c[7] = { 'c', 'e' , 'g', 't', 'w', 'a','d'}, valc;
    c_avg = average(array_c,7);
    valc = median(array_c,7);
    cout<<"\n median "<<valc<<" Avg "<<c_avg<<"\n";
}

The results of the main function are


16 32 36 44 45 47
median 40 Avg 36.6667
2.3 3 4.3 11.3 34.4
median 4.3 Avg 11.06
a c d e g t w
median e Avg 105

Now let us note few points in these code samples. In the median template we have used the shell sort template program we wrote in the previous blog. In the ‘on demand compilation’ the compiler will create the functions for the needed types and call them. In the getAverage function the return type is fixed as double. The template type that is passed should be convertible to type double.

In summary

  1. Template type T should have a default constructor
  2. Template type T should have the operator +=
  3. The template type T should be convertible to double.

Now for so long we have been giving freedom to compiler. We let it decide what is the data type and create a function for that data type. Now what if we want to tell the compiler instead of letting it decide? In the median example, the compiler decided integer median or character median or double median. Now what if we want to tell the compiler to treat all as a double even if we are passing integer or character?

We do this with the angle bracket with the data type at the function call.


Median<double>(array_c,7)

With this special syntax median<>() , we are informing the compiler to create a template for data type double and not to deduce it from the input passed to the function.

Introducing function template and template function


You must be thinking am I being rhetoric? No dear coders exercise some patience.

Function template is body of a function, which has bracketed template keyword. It is not an actual function and is not fully compiled. At lease one call with a data type is needed to instantiate so the compiler can fully compile it and have it linked by the linker. So instance of function template median is instantiated as median (char) or median (int) or median (double).

Template function is an instance of function template. This is created when a function template is instantiated with a particular data type.

Template function is under the umbrella of name-decoration system of compiler and linker. This means


template<class T>
T median(T arr[], int num)
{}

Instantiation for double is not this


Double median(Double arr[], int num)
{}

But it actually is this


Double median<double>(Double arr[], int num)
{}

Use your debugger to find out the actual instantiation and see the full prototype in the generated code or the call stack.

So far we have looked at functions that take up single template parameter. It is possible to create templates that take multiple types. It appears like this


template<typename T1, typename T2, typename T3, … >

Where T1, T2, T3 are typenames.

Lets take a simple example


template<typename T1, typename T2>
void print_nums(T1 num1, T2 num2)
{
  cout<<”First value is “<<num1;
  cout<<”Second value is “<<num2;
}

We can call it as


print_nums(‘a’,2);
print_nums(3.3, 4);
print_nums(7,8.9);

The compiler creates these instances


void print_nums(char,int);
void print_nums(double,int);
void print_nums(int,double);

Do note that the second instantiation and the third instantiation is different. While we have just exchanged the data types. Also note that the compiler does not do automatic conversion, as it does for normal functions. It doesn’t convert short to int or long to int. If they are passed to template types then new function templates are created for each case.

In the next blog let us move into class templates. See you next time..

Happy coding.

To report this post you need to login first.

Be the first to leave a comment

You must be Logged on to comment or reply to a post.

Leave a Reply