Date post: | 27-Oct-2014 |
Category: |
Documents |
Upload: | parvinder-singh |
View: | 22 times |
Download: | 0 times |
Introduction to
C++ TEMPLATES
C++ Training for AT&T MOTOPLYR Team
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
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
What is a Template ?
C++ supports following syntax for templates.
>--export--<--template--<--template_parameter_list-->--declaration--><
(Optional)
This syntax is valid for both template classes and function.
A template declaration can appear as a namespace scope or class scope declaration.
export keyword is optional. It is not supported by most compilers including g++.
General Syntax for C++ Templates
General Syntax for C++ Templates (Contd.)
The template_parameter_list is a comma-separated list of the following kinds of template parameters:
a) non-type b) type
c) template d) default
The declaration is one of the following:
* a declaration or definition of a function or a class.
* a definition of a member function or a member class of a class template.
* a definition of a static data member of a class template.
* a definition of a static data member of a class nested within a class template.
* a definition of a member template of a class or class template.
A template declaration can appear as a namespace scope or class scope declaration.
General Syntax for C++ Templates (Contd.) Here the compiler would create three objects. The
following table shows the definitions of these three objects if they were written out in source form as regular classes, not as templates:
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.
class Key<int> i; class Key<char*> c; class Key<mytype> m;
class Key{ int k; int * kptr; int length;public: Key(int); // ...};
class Key{ char* k; char** kptr; int length;public: Key(char*); // ...};
class Key{ mytype k; mytype* kptr; int length;public: Key(mytype); // ...};
Type Template Parameters
The following is the syntax of a type template parameter declaration:
>>-+-class----+--identifier--+---------+-----------------------><
'-typename-' '-=--type-'
The identifier is the name of a type. For exampletemplate<class A>
Class ABC{
//....
Here A corresponds to the type. To declare an object we will write.
ABC<int> a1; // Note we have passed int as argument while declaring the object.
Non-Type Template Parameters
We can also have the following in the parameter list of the template.
* integral or enumeration
* pointer to object or pointer to function
* reference to object or reference to function
* pointer to class member(TBD)
Non-Type Template Parameters
For example, if the templates are defined like this.
template<int a[4]> struct A {};
template<int f(int)> struct B {};
template<int> struct C{};
template<int& b> struct D {D(){cout<<"struct D "<<endl;}};
enum an_enum{X,Y,Z};
template<an_enum> struct E {E(){cout<<"struct E"<<endl;}};
Then their objects can be declared like this.int g(int a) {return 0;}
int i;
A<&i> x;
B<&g> y;
C<100> z; // Here C<i> would be wrong
D<i> s; // Here the lvalue is required.
E<X> t; // passed enum variable
Non-Type Template Parameters(Contd.)
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 ParametersThe 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.
template<class E> class F{
E g;
};
int main(){
C<F> h; // Notice how are we declaring the object
system("PAUSE");
return 0;
}
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 Type Arguments
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;
}
Template Non-Type Argumentstemplate <class type, int size = 100> // size is a non-type parameter
class Arr{
type stk[size];
public:
Arr(){cout<<"\nArr const\n";}
};
template <int s = 100> class ABCD{ const static int j = s; };
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;
ABCD<47-17> ABCD2; // create ABCD template instance of size 30(=47-17)
ABCD<> ABCD3;//Take default value i.e. 100
system(“PAUSE”);
return 0;
}
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;
};
int main()
{
A<B<float>,int> A1;
system("PAUSE");
return 0;
}
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.
An example of a template class
//template.h. This file contains both declarations and definition of the template.
template<class T, int Size> class Stack {
T stk[Size];
int top;
Public:
Stack();
int push(T);
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.
Operator overloading functions and static members of a template class
template<class T>
class X {
public:
static T static_var;
T operator+(T);
};
template<class T> T X<T>::static_var;
template<class T>
T X<T>::operator+(T arg1) { return arg1; };
int main()
{
X<char> a;
X<int> b;
a +'z';
b + 4;
}
Consider the following class Asia. It contains one nested class India.
class Asia
{
public:
Class India{
int Mohali, Mumbai, Noida;
};
};
Now consider following template.
template<class Z>
class Type_Name
{
Z::India * Sachin;
};
This kind of declaration is ambiguous. Any standard compiler will produce an error for this.
The Keyword “typename”
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.
The Keyword “typename” (Contd.)
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.
Function Templates
Template Argument Deduction
When you call a template function, you may omit any template argument that the compiler can determine or deduce by the usage and context of that template function call. But this is not possible every-time.
template <class T> class vector{ /* ... */ };
template <class T> T* create(); // make a T and return a pointer to it
void f()
{
vector<int > v ; // class, template argument ‘int’
int* p = create<int>(); // function, template argument ‘int’
}
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: can’t deduce T
implicit_cast<double>(i); // T is double; U is int
implicit_cast<char,double>(i); // T is char; U is double
implicit_cast<char*,int>(i); // T is char*; U is int; error: cannot convert int to char*
}
Template Argument Deduction
It is not possible every time to deduce the function. For example.
template<class U> int h(){cout<<"func h()"<<endl;}
int main()
{
h<float>(); // Ok, Will work fine
h(); //error can't deduce the function
system("PAUSE");
return 0;
}
Overloading Function Templates
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.
Non-template functions take precedence over template functions.
Overloading Function Templates(Contd.)#include <iostream>
using namespace std;
template<class T> void f(T x, T y) { cout << "Template" << endl;}
void f(int w, int z) { cout << "Non-template" << endl; }
int main() {
f( 1 , 2 );
f('a', 'b');
f( 1 , 'b');
}
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'.
Overloading Function Templates Rulestemplate<class T> T sqrt(T);
template<class T>complex <T> sqrt (complex <T>);
double sqrt(double);
void f(complex<double>z)
{
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 non-template 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.
Practice Code Snippet
template<class T> void f(T) { }
template<class T> void f(T*) { }
template<class T> void f(const T*) { }
template<class T> void g(T) { }
template<class T> void g(T&) { }
template<class T> void h(T) { }
template<class T> void h(T, ...) { }
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.
h(q); // Ambiguous. Ellipses do not affect partial ordering.
}
There are four kinds of relationships between template classes and their friend functions :
One-to-many: A non-template function may be a friend to all template class instantiations.
Many-to-one: All instantiations of a template function may be friends to a regular non-template class.
One-to-one: A template function instantiated with one set of template arguments may be a friend to one template class instantiated with the same set of template arguments. This is also the relationship between a regular non-template class and a regular non-template friend function.
Many-to-many: All instantiations of a template function may be a friend to all instantiations of the template class.
Friends And Templates
class B{
template<class V> friend int j(); //many-to-one
};
template<class S> int g();
template<class T> class A {
public:
friend int e(); // one-to-many
friend int f(T); // one-to-one
friend int g<T>(); // one-to-one
template<class U> friend int h(); //many-to-many
};
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.
These relationships also apply to friend classes.
Friends And Templates (Contd.)
Class Template
friend declaration in class template X
Results of giving friendship
template class <T> class X friend void f1() ; makes f1() a friend of all instantiations of template X. For example, f1() is a friend of
X<int>, X<A>, and X<Y>. template class <T> class X friend void f2(X<T>&) ; 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>.
template class <T> class X friend A::f4() ; makes A::f4() a friend of all instantiations of template X. For example, A::f4() is a friend
of X<int>, X<A>, and X<Y>. template class <T> class X
friend C<T>::f5(X<T>&); For a particular type T for example, float, makes C<float>::f5(X<float>&) a friend of class X<float> only. C<float>::f5(x<float>&) cannot be a friend of class X<A>.
template class <T> class X
friend class Y; makes every member function of class Y a friend of every template class produced from
the class template X. template class <T> class X
friend class Z<T>; when a template class is instantiated with a particular type T, such as a float, all members
of class Z<float> become friends of template class X<float>.
Friends And Templates (Contd.)
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
Explicit Template Specialization
When you instantiate a template with a given set of template arguments the compiler generates a new definition based on those template arguments.
We can override this behavior of definition generation. You can instead specify the definition the compiler uses for a given set of template arguments.
This is called explicit specialization.
We can explicitly specialize any of the following:
* Function or class template
* Member function of a class template
* Static data member of a class template
* Member class of a class template
* Member function template of a class template
* Member class template of a class template
Explicit Template Specialization (Contd.)The template<> prefix indicates that the following template declaration takes no template parameters.
The declaration_name is the name of a previously declared template.
We can forward-declare an explicit specialization so the declaration_body is optional, at least until the specialization is referenced.
Explicit Template Specialization (Contd.)
template<class T = float, int i = 5> class A { Int value; public: A();};
template<> class A<> { public: A(); };template<> class A<double, 10> { public: A(); };
template<class T, int i> A<T, i>::A() : value(i) { cout << "Primary template, " << "non-type argument is " << value << endl;} A<>::A() { cout << "Explicit specialization "<< "default arguments" << endl;} A<double, 10>::A() { cout << "Explicit specialization "<< "<double, 10>" << endl;}
int main() A<int,6> x; A<> y; A<double, 10> z; return 0;}
Output :
Primary template non-type argument is: 6Explicit specialization default argumentsExplicit specialization <double, 10>
Explicit Template Specialization (Contd.)
A declaration of a primary template must be in scope at the point of declaration of the explicit specialization.
In other words, an explicit specialization declaration must appear after the declaration of the primary template.
For example, the compiler will not allow the following:
template<> class A<int>;//error
template<class T> class A;
// or
namespace itaas{
template<class T> class A;
};
template<> class A<int>;//error
Explicit Template Specialization (Contd.)
You can use the name of an explicit specialization that has been declared but not defined the same way as an incompletely defined class. The following example demonstrates this:
template<class T> class X { };
template<> class X<char>;
X<char>* p;
X<int> i;
// X<char> j;
The compiler does not allow the declaration X<char> j because the explicit specialization of X<char> is not defined.
Explicit Template Specialization (Contd.)
A member of an explicitly specialized class is not implicitly instantiated from the member declaration of the primary template.
We have to explicitly define members of a class template specialization.template<class T> class A {
public:
void f(T);
};
template<> class A<int> {
public:
int g(int);
};
int A<int>::g(int arg) { return 0; }
int main() {
A<int> a;
a.g(1234);
}
The explicit specialization A<int> contains the member function g(), which the primary template does not.
Explicit Template Specialization (Contd.)
If you explicitly specialize a template, a member template, or the member of a class template, then you must declare this specialization before that specialization is implicitly instantiated. For example, the compiler will not allow the following code:
template<class T> class A { };
void f() { A<int> x; }
template<> class A<int> { };
int main() { f(); }
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.
Explicit Template Specialization (Contd.)
In a function template specialization, a template argument is optional if the compiler can deduce it from the type of the function arguments.
The explicit specialization template<> void func(X<int>) is equivalent to template<> void func<int>(X<int>).
We cannot specify default function arguments in a declaration or a definition for any of the following:
* Explicit specialization of a function template
* Explicit specialization of a member function template
For example, the compiler will not allow the following code:
template<class T> void f(T a) { };
template<> void f<int>(int a = 5) { };
Explicit Template Specialization (Contd.)
Each instantiated class template specialization has its own copy of any static members. You may explicitly specialize static members. The following example demonstrates this:template<class T> class X { public: static T v; static void f(T); }; template<class T> T X<T>::v = 0; template<class T> void X<T>::f(T arg) { v = arg; } template<> char* X<char*>::v = "Hello"; template<> void X<float>::f(float arg) { v = arg * 2; }
int main() { X<char*> a, b; X<float> c; c.f(10); }
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).
Explicit Template Specialization (Contd.)
We can nest member templates within many enclosing class templates.
If you explicitly specialize a template nested within several enclosing class templates, you must prefix the declaration with template<> for every enclosing class template you specialize.
You may leave some enclosing class templates unspecialized, however you cannot explicitly specialize a class template unless its enclosing class templates are also explicitly specialized. definition that would output "Template 7" because the enclosing class of class Y (which is class X) is not explicitly specialized.A friend declaration cannot declare an explicit specialization.
Explicit Template Specialization (Contd.)The following example demonstrates explicit specialization of nested member
templates:template<class T> class X {
public:
template<class U> class Y {
public:
template<class V> void f(U,V);
void g(U); };
};
template<class T> template<class U> template<class V> void X<T>::Y<U>::f(U, V) { cout << "Template 1" << endl; }
template<class T> template<class U> void X<T>::Y<U>::g(U) { cout << "Template 2" << endl; }
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
Explicit Template Specialization (Contd.)The compiler would not allow the template specialization
definition that would output "Template 6" because it is attempting to specialize a member (function f()) without specialization its containing class (Y).
The compiler would not allow the template specialization definition that would output "Template 7" because the enclosing class of class Y (which is class X) is not explicitly specialized.
A friend declaration cannot declare an explicit specialization.
We cannot combine the parameter lists for a template class and its enclosing class.
Partial Template SpecializationWhen we instantiate a class template, the compiler creates a
definition based on the template arguments you have passed. Alternatively, if all those template arguments match those of an
explicit specialization, the compiler uses the definition defined by the explicit specialization.
A partial specialization is a generalization of explicit specialization.
An explicit specialization only has a template argument list. A partial specialization has both a template argument list and a
template parameter list. The compiler uses the partial specialization if its template
argument list matches a subset of the template arguments of a template instantiation.
The compiler will then generate a new definition from the partial specialization with the rest of the unmatched template arguments of the template instantiation.
You cannot partially specialize function templates.
Partial Template Specialization SyntaxPartial specialization syntax
>>-template--<template_parameter_list>--declaration_name--------> >--<template_argument_list>--declaration_body------------------><
The declaration_name is a name of a previously declared template.
Note that we can forward-declare a partial specialization so that the declaration_body is optional.
Partial Template Specialization Syntax (Contd.)
template<class T, class U, int I> struct X {void f() { cout << "Primary template" << endl; } }; template<class T, int I> struct X<T, T*, I> { void f() { cout << "Partial specialization 1" << endl; } }; template<class T, class U, int I> struct X<T*, U, I> {void f() { cout << "Partial specialization 2" << endl; } }; template<class T> struct X<int, T*, 10> {void f() { cout << "Partial specialization 3" << endl;
} }; template<class T, class U, int I> struct X<T, U*, I> { void f() { cout << "Partial specialization 4" << endl; } }; int main() { X<int, int, 10> a; X<int, int*, 5> b; X<int*, float, 10> c; X<int, char*, 10> d; X<float, int*, 10> e; // X<int, int*, 10> f; a.f(); b.f(); c.f(); d.f(); e.f(); }
Partial Template Specialization Syntaxoutput:Primary template
Partial specialization 1
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.
Partial Template Specialization SyntaxPrimary templates do not have template argument lists; this list
is implied in the template parameter list.
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> { };
Partial Template Specialization SyntaxThe type of a non-type template argument cannot depend on a
template parameter of a partial specialization. The compiler will not allow the following partial specialization:
template<class T, T i> class X { };
// Invalid partial specialization
template<class T> class X<T, 25> { };
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.
Inheritance In Class TemplatesInheritance works in the template in the same way as that of
non-template classes. Except that the corresponding template class would be generated just at the time of instantiation.
We can have
a) Template Base class – Template Derived class
b) Non-Template Base class – Template Derived class
c) Template Base class – Non-Template Derived class
The template/class header for cases (a) and (c) may seem similar. But there is a difference.
Inheritance In Class Templates (Contd.)template <class T> class A{ // Template Base Class
int b;
public:
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;
}
Inheritance In Class Templates (Contd.)class A{ // Non-Template Derived Class
int b;
public:
A(int d):b(d){}
virtual void show(){ cout<<"b is "<<b<<endl;}
};
template<class T> class F: public A{ // Template Derived Class
int g;
public:
T h;
F(int i,int j,T k):A(i),g(j),h(k){}
void show(){ cout<<"g is "<<g<<endl;cout<<"h is "<<h<<endl;A::show();};
};
int main()
{
F<int> f1(2,4,87);
f1.show();
system("PAUSE");
return 0;
}
Inheritance In Class Templates (Contd.)
template <class T> class A{ // Template Base Class
int b;
public:
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>{ // Non-Template Derived Class. No dependency on template variable T
int g;
public:
F(int i,int j,T k):A<T>(i,k),g(j){}
void show(){ cout<<"g is "<<g<<endl;A<T>::show();};
};
int main()
{
F<int> f1(2,4,87);
f1.show();
system("PAUSE");
return 0;
}
Base-Derived conversions in Templatestemplate <class T> class Ptr{ T p; public: Ptr(){} Ptr(T); template <class T2> operator Ptr<T2>(); // Important for compiling};template <class T> Ptr<T>::Ptr(T ptr) { p = ptr;}template <class T> template <class T2> Ptr<T>::operator Ptr<T2>(){return static_cast<Ptr<T2> >(p);}
class Shape{ };class Circle : public Shape{ };class Triangle : public Shape{};
void func(Ptr<Shape*> shape){ cout<<"func gets called"<<endl; }
int main(){ Ptr<Shape*> ptr1; func(ptr1); Ptr<Circle*> ptr2; func(ptr2); system("PAUSE"); return 0;}
Output:
func gets calledfunc gets called
This is also an example of smart pointers.
Code Organization with TemplatesWhen working with normal (non-template) classes, we
generally first create a header file containing the definition of a class and a source code file which contains the definition of that class.
Then we compile that source file and link it with other translational units.
But in case of templates this is not possible in a normal way.
Code Organization with Templates
// template_itaas.h#ifndef TEMPLATE_ITAAS_H__#define TEMPLATE_ITAAS_H__namespace itaas{template <class T> class itaas_1{T a;public:itaas_1(T);void show(); };};#endif
// template_itaas.cpp#include <iostream>#include "template_itaas.h"using namespace std;using namespace itaas;template <class T> itaas_1<T>::itaas_1(T t1){ a = t1;}
template <class T> void itaas_1<T>::show(){cout<<"value of a is "<<a<<endl;}
// main.cpp#include <iostream>#include "template_itaas.h"using namespace std;using namespace itaas;
int main(){ itaas_1<int> i1(10); system("PAUSE"); return EXIT_SUCCESS;}
Code Organization with TemplatesThe previous example if compiled by
g++ main.cpp template_itaas.cpp –I./ -o final
It will give an error. [Linker error] undefined reference to `itaas::itaas_1<int>::itaas_1(int)'
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) Include the template source file in main source code file.
b) 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.)
c) Explicit instantiation of the template class in the template source file for some common data types.
Code Organization with Templates (Contd.)
For this we can
a) Include the template source file in main source code file.
b) 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.)
c) Explicit instantiation of the template class in the template source file for some common data types.
d) We can use keyword export. But this key word is nit supported by many compilers, including g++. Currently, compiler named Comeau is one of the main stream compiler which support export.
Uses of TemplatesIn general C++ templates are used in
a) Template Meta-Programming (Also known as TMP)
b) Implementing Smart Pointers such as auto-ptr.
c) Deciding the policy for a certain task in an algorithm.
d) Standard Template Library (Also known as STL)
Template Meta-ProgrammingTemplate 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
• “The C++ Programming Language” by Bjarne Stroustrup.
http://publib.boulder.ibm.com/infocenter/comphelp/v7v91/index.jsp
QUIZQues 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 2 : How can we hide the definitions of my template code ?
Ques 3 : How can we declare separate template declarations/ definitions for pointer and non-pointer types ?
QUIZQues 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 ?
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 g(int a) {return 0;}
int main()
{
int i;
A<&i> x;
B<&g> y;
C<100> z; // Here C<i> would be wrong
system("PAUSE");
return 0;
}
QUIZ