Professional Documents
Culture Documents
C++Training 4
C++Training 4
Introduction to
C++ TEMPLATES
Points of Discussion
What is a Template ? Template Parametrization Template Arguments Class Templates Function Templates Template Instantiation
Template Specialization
Inheritance in Templates Code Organization with Templates General Uses of Template
References
Quiz
What is a Template ?
A template describes a set of related classes or set of related functions in which a list of parameters in the declaration describe how the data type of the members of the set vary.
The compiler generates new classes or functions only when you declare object for template classes or explicitly instantiates a template class for a particular data type or call template functions with template arguments; this process is called template instantiation, C++ provides two kinds of templates :a) Class Template b) Function Template
>--export--<--template--<--template_parameter_list-->--declaration--><
(Optional)
class Key<int> i;
class Key { int k; int * kptr; int length; public: Key(int); // ... };
class Key<char*> c;
class Key { char* k; char** kptr; int length; public: Key(char*); // ... };
class Key<mytype> m;
class Key { mytype k; mytype* kptr; int length; public: Key(mytype); // ... };
Note that these three classes have different names. The arguments contained within the angle braces are not just the arguments to the class names, but part of the class names themselves. Key<int> and Key<char*> are class names.
A template parameter can also be used in the definition of subsequent template parameters.
template<class T,T def_val> class Cont { /* ... */ };
You cannot declare a non-type template parameter as a floating point, class, or void type. For example following is invalid.
template<double x> class Cont { /* ... */ }; // invalid non-type parameter // can't be floating template<int x> class Cont { /* ... */ }; // valid
Non-type template parameters are not lvalues. But when we take reference as a template parameter, the compiler wants lvalue.
Template-Template Parameters
The following is the syntax of a template template parameter declaration:
>>-template--<--template-parameter-list-->--class--+------+--+------------------+->< '-identifier-' ' '-=--id-expression-
Example :
template<template<class A> class B> class C{
B<int> d;// Creating an instance of template B only }; // after instance of template C is created.
Please also note that in above case constructor of class F will be called first.
Default-Template Parameters
It follows the same syntax as that for the other types.
//template<class A = int,class Z> class B{ // Error template<class Z,class A = int> class B{ // Valid
A d; }; int main(){ B<float> B1; B<float,char> B2;
system("PAUSE");
return 0; }
If all the template parameters have a default value then that template instance can be declared with empty <> too.
Template Arguments
There are three kinds of template arguments corresponding to the four types of template parameters: * type
* non-type
* template
template<class Z,class A = int> class B{ }; int main(){ B<float,char> B1;// Template Type Arguments B<float> B2;// Template Type Arguments. Second argument would be taken as // default. B<int()> B3;// Again Template Type Argument. Compiler consider int() as a type. return 0; }
int main(){ Arr<float,200> A1;// Template Non-Type Argument '200' Arr<int> A2;// Create an array of integers with size 100 ABCD<50> ABCD1;
Template-Template Arguments
A template argument for a template-template parameter is the name of a class template.
template<class T, class U> class A { T x; }; template<class U> class B {
short y;
U z; };
Class Templates
The relationship between a class template and an individual class is like the relationship between a class and an individual object.
An individual class defines how a group of objects can be constructed, while a class template defines how a group of classes can be generated. There is a distinction between the terms class template and template class: Class template is a template used to generate template classes. We can have the definition of the template in the header file. Template class is an instance of a class template.
int pop();
}; template<class T,int N> class Stack<T,N>::Stack() { top = 0;
}
// Other functions definition.
Now we can include this header file in our source file and there would be no problem of multiple declaration error.
This kind of declaration is ambiguous. Any standard compiler will produce an error for this.
The tynename keyword tells the compiler that an unknown identifier is a type.
template<class Z> class Type_Name { typename Z::India * Sachin; // compiler will treat Z::India as a type };
typename can also be used in place of the keyword class in template parameter declarations.
Function Templates
A function template defines how a group of functions can be generated. A non-template function is not related to a function template, even though the non-template function may have the same name and parameter profile as those of a specialization generated from a template. A non-template function is never considered to be a specialization of a function template.
One common use of explicit specification is to provide a return type for a template function:
template <class T , class U > T implicit_cast (U u ) { return u ; } void g(int i ) { implicit_cast(i); // error: cant deduce T
int main() { h<float>(); // Ok, Will work fine h(); //error can't deduce the function system("PAUSE"); return 0; }
If you call the name of an overloaded function template, the compiler will try to deduce its template arguments and check its explicitly declared template arguments.
If successful, it will instantiate a function template specialization, then add this specialization to the set of candidate functions used in overload resolution. The compiler proceeds with overload resolution, choosing the most appropriate function from the set of candidate functions.
Output :
Non-template
Template
Non-template
Argument deduction fails for the function call f(1, 'b') as the compiler does not generate any template function specialization and overload resolution does not take place. The non-template function resolves this function call after using the standard conversion from char to int for the function argument 'b'.
{
sqrt(2);// sqrt<int>(int) sqrt(2.0) ; // sqrt(double) sqrt(z) ; // sqrt<double>(complex<double>) }
we apply the usual function overload resolution rules to these specializations and
all ordinary functions: [1] Find the set of function template specializations that will take part in overload resolution. [2] If two template functions can be called then choose that is more specialized than the other. [3] If a template function argument has been determined by template argument deduction, that argument cannot also have promotions, standard conversions, or user-defined conversions applied. [4] If a non-template function and a specialization are equally good matches, the nontemplate function is preferred. 5] If no match is found, the call is an error. If we end up with two or more equally good matches, the call is ambiguous and is an error.
int main() { const int *p; f(p); // template<class T> void f(const T*) { }
int q; g(q); // Ambiguous. g(T) and g(T&) will considered same while calling.
In case of f(), you may get the following error from compiler.
The friend function declaration "f" will cause an error when the enclosing template class is instantiated with arguments that declare a friend function that does not match an existing definition.
The function declares only one function because it is not a template but the function type depends on one or more template parameters.
Class Template
template class <T> class X
For a particular type T for example, float, makes f2(X<float>&) a friend of class X<float> only. f2(x<float>&) cannot be a friend of class X<A>. makes A::f4() a friend of all instantiations of template X. For example, A::f4() is a friend
friend A::f4() ;
friend class Y;
Template Instantiation
The process of generating a class declaration from a template class and a template argument is often called template instantiation. Similarly, a function is generated (instantiated) from a template function plus a template argument.
template<class L> class Key { //.... } template<class T> void func(){ //... } template class Key<char>;//Explicit instantiation template void func<float>();//Explicit instantiation
void g(){
Key<int> abc;//Implicit instantiation func<int>();//Implicit instantiation }
Note that template instance is created only when compiler hits the template instantiation statement.
Template Specialization
The process of creating a new definition of a function, class, or member of a class from a template declaration and one or more template arguments is called template instantiation. The definition created from a template instantiation is called a template specialization. A primary template is the template that is being specialized.
template<class L> class Key { //.... }; //Primary Template template<> class Key<int> { //.... }; //Specialization. template<> class Key<float> {//... }; //Specialization.
Note that if template instantiation is to be done for specialized instances, then there is no need for the definition of the primary template. Template specialization can be done in two ways. [1] Explicit Specialization [2] Partial Specialization
Output :
Primary template non-type argument is: 6 Explicit specialization default arguments Explicit specialization <double, 10>
// or
// X<char> j;
The compiler does not allow the declaration X<char> j because the explicit specialization of X<char> is not defined.
The explicit specialization A<int> contains the member function g(), which the primary template does not.
The compiler will not allow the explicit specialization template<> class A<int> { }; because function f() uses this specialization (in the construction of x) before the specialization.
This code explicitly specializes the initialization of static data member X::v to point to the string "Hello" for the template argument char*. The function X::f() is explicitly specialized for the template argument float. The static data member v in objects a and b point to the same string, "Hello". The value of c.v is equal to 20 after the call function call c.f(10).
template<> template<> void X<int>::Y<int>::g(int) { cout << "Template 3" << endl; }
template<> template<> template<class V> void X<int>::Y<int>::f(int, V) { cout << "Template 4" << endl; } template<> template<> template<> void X<int>::Y<int>::f<int>(int, int) { cout << "Template 5" << endl; } // template<> template<class U> template<class V> // void X<char>::Y<U>::f(U, V) { cout << "Template 6" << endl; } // template<class T> template<> // void X<T>::Y<float>::g(float) { cout << "Template 7" << endl; }
int main() { X<int>::Y<int> a; X<char>::Y<char> b; a.f(1, 2); a.f(3, 'x'); a.g(3); b.f('x', 'y'); b.g('z'); }
The following is the output of the above program: Template 5 Template 4 Template 3 Template 1 Template 2 on
We cannot combine the parameter lists for a template class and its enclosing class.
Note that we can forward-declare a partial specialization so that the declaration_body is optional.
Partial specialization 2
Partial specialization 3 Partial specialization 4
The compiler would not allow the declaration X<int, int*, 10> f() because it can match template struct X<T, T*, I>, template struct X<int, T*, 10>, or template struct X<T, U*, I>, and none of these declarations are a better match than the others. Each class template partial specialization is a separate template. We must provide definitions for each member of a class template partial specialization.
Template parameters specified in a primary template but not used in a partial specialization are omitted from the template parameter list of the partial specialization. The order of a partial specialization's argument list is the same as the order of the primary template's implied argument list.
In a template argument list of a partial template parameter, we cannot have an expression that involves non-type arguments unless that expression is only an identifier.
template<int I, int J> class X { }; // Invalid partial specialization template<int I> class X <I * 4, I + 3> { }; // Valid partial specializations template <int I> class X <I, I> { }; template <typename T> class Z <T,45*78-98-78+156-10000> { };
A partial specialization's template argument list cannot be the same as the list implied by the primary template. We cannot have default values in the template parameter list of a partial specialization.
T c;
A(int d,T e):b(d),c(e){} virtual void show(){ cout<<"b is "<<b<<endl;cout<<"c is "<<c<<endl;} }; template<class T> class F: public A<T>{ //Template Derived class int g; public: T h; F(int i,int j,T k):A<T>(i,k),g(j),h(k){} void show(){ cout<<"g is "<<g<<endl;cout<<"h is "<<h<<endl;A<T>::show();}; }; int main() { F<int> f1(2,4,87); f1.show(); system("PAUSE"); return 0; }
return 0;
}
As at the time of linking no instance of the template class was instantiated. Template instantiation can be delayed upto the point of linking. But here at the time of linking there was no instance of itaas_1<int>. For this we can a) b) Include the template source file in main source code file. Define all the members of template in the header file.(STL is implemented in the same way. Although, they are the part namespace std but are defined in the header files only.) Explicit instantiation of the template class in the template source file for some common data types.
c)
a)
b)
c) d)
Uses of Templates
In general C++ templates are used in a) Template Meta-Programming (Also known as TMP)
b)
c) d)
Template Meta-Programming
Template metaprogramming is a meta-programming technique in which templates are used by a compiler to generate temporary source code, which is merged by the compiler with the rest of the source code and then compiled. The output of these templates include compile time constants, data structures, and complete functions. The use of templates can be thought of as compile time execution. Compiler act as an interpreter. Its example is
template <int N> struct Factorial { enum { value = N * Factorial<N - 1>::value }; }; template <> struct Factorial<0> { enum { value = 1 }; }; // Factorial<4>::value == 24 // Factorial<0>::value == 1 void foo() { int x = Factorial<4>::value; // == 24 int y = Factorial<0>::value; // == 1 }
References
QUIZ
Ques 1 : What would be the output ?
void f(int a){cout<<"non-template\n";} template <class T> void f(int h){cout<<"template\n";} int main() { // f(); f(457); system("PAUSE"); return 0; }
Ques 3 : How can we declare separate template declarations/ definitions for pointer and non-pointer types ?
QUIZ
Ques 4 : If we put the following operator definition in the code, the code still compiles and this operator function gets called.
ostream& operator<<(ostream& os,string str){ //... }
Why is this function does not produce an error as string is a type provided by the namespace std and the operator << is already handled in the namepsacae ? Why don't we get the error of multiple declaration ?
QUIZ
Will the following code compile ?
template<int *a> struct A {A(){cout<<"struct A"<<endl;}}; template<int f(int)> struct B {B(){cout<<"struct B"<<endl;}}; template<int> struct C{C(){cout<<"struct C"<<endl;}};
int main() { int i; A<&i> x; B<&g> y; C<100> z; // Here C<i> would be wrong system("PAUSE"); return 0; }