The following code defines a function template. The keyword, template <typename T, int size>, tells the compiler that what follows is a function template:
template <typename T, int size>
void sort ( T input[] ) {
for ( int i=0; i<size; ++i) {
for (int j=0; j<size; ++j) {
if ( input[i] < input[j] )
swap (input[i], input[j] );
}
}
}
The line, void sort ( T input[] ), defines a function named sort, which returns void and receives an input array of type T. The T type doesn't indicate any specific data type. T will be deduced at the time of instantiating the function template during compile time.
The following code populates an integer array with some unsorted values and prints the same to the terminal:
int a[10] = { 100, 10, 40, 20, 60, 80, 5, 50, 30, 25 };
cout << "nValues in the int array before sorting ..." << endl;
copy ( a, a+10, ostream_iterator<int>( cout, "t" ) );
cout << endl;
The following line will instantiate an instance of a function template for the int data type. At this point, typename T is substituted and a specialized function is created for the int data type. The scope-resolution operator in front of sort, that is, ::sort(), ensures that it invokes our custom function, sort(), defined in the global namespace; otherwise, the C++ compiler will attempt to invoke the sort() algorithm defined in the std namespace, or from any other namespace if such a function exists. The <int, 10> variable tells the compiler to create an instance of a function, substituting typename T with int, and 10 indicates the size of the array used in the template function:
::sort<int, 10>( a );
The following lines will instantiate two additional instances that support a double array of 5 elements and a string array of 6 elements respectively:
::sort<double, 5>( b );
::sort<string, 6>( names );
If you are curious to know some more details about how the C++ compiler instantiates the function templates to support int, double, and string, you could try the Unix utilities, nm and c++filt. The nm Unix utility will list the symbols in the symbol table, as follows:
nm ./a.out | grep sort
00000000000017f1 W _Z4sortIdLi5EEvPT_
0000000000001651 W _Z4sortIiLi10EEvPT_
000000000000199b W _Z4sortINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEELi6EEvPT_
As you can see, there are three different overloaded sort functions in the binary; however, we have defined only one template function. As the C++ compiler has mangled names to deal with function overloading, it is difficult for us to interpret which function among the three functions is meant for the int, double, and string data types.
However, there is a clue: the first function is meant for double, the second is meant for int, and the third is meant for string. The name-mangled function has _Z4sortIdLi5EEvPT_ for double, _Z4sortIiLi10EEvPT_ for int, and _Z4sortINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEELi6EEvPT_ for string. There is another cool Unix utility to help you interpret the function signatures without much struggle. Check the following output of the c++filt utility:
c++filt _Z4sortIdLi5EEvPT_
void sort<double, 5>(double*)
c++filt _Z4sortIiLi10EEvPT_
void sort<int, 10>(int*)
c++filt _Z4sortINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEELi6EEvPT_
void sort<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, 6>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*)
Hopefully, you will find these utilities useful while working with C++ templates. I'm sure these tools and techniques will help you to debug any C++ application.