Templates

Template
Templates are a feature of the C++ programming language that allow functions and classes to operate with generic types. This allows a function or class to work on many different data types without being rewritten for each one. This is effectively a Turing-complete language.
Templates are of great utility to programmers in C++, especially when combined with multiple inheritance and operator overloading. The C++ Standard Library provides many useful functions within a framework of connected templates.
Major inspirations for C++ templates were the parametrized modules provided by CLU and the generics provided by Ada.
A template is a blueprint or formula for creating a generic class or a function. The library containers like iterators and algorithms are examples of generic programming and have been developed using template concept.
There is a single definition of each container, such as vector, but we can define many different kinds of vectors for example, vector or vector .
There are two kinds of templates: function templates and class templates. (A third kind, variable templates, is expected to feature in C++14.)
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.
Function templates, like macros, enable software reuse. Unlike macros, function templates help eliminate many types of errors through the scrutiny of full C++ type checking
All function-template definitions begin with keyword template followed by a list of template parameters to the function template enclosed in angle brackets (< and >); each template parameter that represents a type must be preceded by either of the interchangeable keywords class or typename, as in
template< typename BorderType, typename FillType >
The type template parameters of a function-template definition are used to specify the types of the arguments to the function, to specify the return type of the function and to declare variables within the function. The function definition follows and appears like any other function definition. Note that keywords typename and class used to specify function-template parameters actually mean "any built-in type or user-defined type."
Example: -
#include < iostream >
#include < string >
using namespace std;
template
inline T const& Max (T const& a, T const& b)
{
return a < b ? b:a;
}
int main ()
{
int i = 39;
int j = 20;
cout << "Max(i, j): " << Max(i, j) << endl;
double f1 = 13.5;
double f2 = 20.7;
cout << "Max(f1, f2): " << Max(f1, f2) << endl;
string s1 = "Hello";
string s2 = "World";
cout << "Max(s1, s2): " << Max(s1, s2) << endl;
return 0;
}
Max(i, j): 39
Max(f1, f2): 20.7
Max(s1, s2): World
Function template instantiation
A function template by itself is not a type, or a function, or any other entity. No code is generated from a source file that contains only template definitions. In order for any code to appear, a template must be instantiated: the template arguments must be determined so that the compiler can generate an actual function (or class, from a class template).
Explicit instantiation
* Explicit instantiation; : - Explicit instantiation definition without template argument deduction
* template return-type name ( parameter-list ); : - Explicit instantiation definition with template argument deduction
* extern template return-type name < argument-list > ( parameter-list ) ; : - Explicit instantiation declaration without template argument deduction
* extern template return-type name ( parameter-list ) ; : - Explicit instantiation declaration with template argument deduction
An explicit instantiation definition forces instantiation of the function or member function they refer to. It may appear in the program anywhere after the template definition, and for a given argument-list, is only allowed to appear once in the program.
An explicit instantiation declaration (an extern template) prevents implicit instantiations: the code that would otherwise cause an implicit instantiation has to use the explicit instantiation definition provided somewhere else in the program.
template
void f(T s)
{
std::cout << s << '\n';
}
template void f(double); // instantiates f(double)
template void f<>(char); // instantiates f(char)
template void f(int); // instantiates f(int)
Implicit instantiation
When code refers to a function in context that requires the function definition to exist, and this particular function has not been explicitly instantiated, implicit instantiation occurs. The list of template arguments does not have to be supplied if it can be deduced from context
#include
template
void f(T s)
{
std::cout << s << '\n';
}
int main()
{
f(1); // instantiates and calls f(double)
f<>('a'); // instantiates and calls f(char)
f(7); // instantiates and calls f(int)
void (*ptr)(std::string) = f; // instantiates f(string)
}
Template argument deduction
In order to instantiate a function template, every template argument must be known, but not every template argument has to be specified. When possible, the compiler will deduce the missing template arguments from the function arguments. This occurs when a function call is attempted and when an address of a function template is taken.
template To convert(From f);
void g(double d)
{
int i = convert(d); // calls convert(double)
char c = convert(d); // calls convert(double)
int(*ptr)(float) = convert; // instantiates convert(float)
}
Class templates
A class template must be declared before any instantiation of a corresponding template class. A class template definition can only appear once in any single translation unit. A class template must be defined before any use of a template class that requires the size of the class or refers to members of the class.
In the following example, the class template Key is declared before it is defined. The declaration of the pointer keyiptr is valid because the size of the class is not needed. The declaration of keyi, however, causes an error
template class Key; // class template declared,
// not defined yet
//
class Key *keyiptr; // declaration of pointer
//
class Key keyi; // error, cannot declare keyi
// without knowing size
//
template class Key // now class template defined
{ /* ... */ };
If a template class is used before the corresponding class template is defined, the compiler issues an error. A class name with the appearance of a template class name is considered to be a template class. In other words, angle brackets are valid in a class name only if that class is a template class.
The previous example uses the elaborated type specifier class to declare the class template key and the pointer keyiptr. The declaration of keyiptr can also be made without the elaborated type specifier.
template class Key; // class template declared,
// not defined yet
//
Key *keyiptr; // declaration of pointer
//
Key keyi; // error, cannot declare keyi
// without knowing size
//
template class Key // now class template defined
{ /* ... */ };
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.
1. Class template: - is a template used to generate template classes. You cannot declare an object of a class template.
2. Template class: - is an instance of a class template.
* A template definition is identical to any valid class definition that the template might generate, except for the following: -
1. The class template definition is preceded by
* template< template-parameter-list >
where template-parameter-list is a comma-separated list of one or more of the following kinds of template parameters:
* type
*non-type
*template
2. Types, variables, constants and objects within the class template can be declared using the template parameters as well as explicit types (for example, int or char).
A class template can be declared without being defined by using an elaborated type specifier. For example:
* template class Key;
This reserves the name as a class template name. All template declarations for a class template must have the same types and number of template arguments. Only one template declaration containing the class definition is allowed.
* NOte: - When you have nested template argument lists, you must have a separating space between the > at the end of the inner list and the > at the end of the outer list. Otherwise, there is an ambiguity between the extraction operator >> and two template list delimiters.
EXample: -
#include < iostream >
#include < vector >
#include < cstdlib >
#include < string >
#include < stdexcept >
using namespace std;
template
class Stack {
private:
vector elems; // elements
public:
void push(T const&); // push element
void pop(); // pop element
T top() const; // return top element
bool empty() const{ // return true if empty.
return elems.empty();
}
};
template
void Stack::push (T const& elem)
{
// append copy of passed element
elems.push_back(elem);
}
template
void Stack::pop ()
{
if (elems.empty()) {
throw out_of_range("Stack<>::pop(): empty stack");
}
// remove last element
elems.pop_back();
}
template
T Stack::top () const
{ if (elems.empty()) {
throw out_of_range("Stack<>::top(): empty stack");
}
// return copy of last element
return elems.back();
}
int main()
{
try {
Stack intStack; // stack of ints
Stack stringStack; // stack of strings
// manipulate int stack
intStack.push(7);
cout << intStack.top() < // manipulate string stack
stringStack.push("hello");
cout << stringStack.top() << std::endl;
stringStack.pop();
stringStack.pop();
}
catch (exception const& ex) {
cerr << "Exception: " << ex.what() < return -1;
}
}
Output: -
7
hello
Exception: Stack<>::pop(): empty stack
Template specialization
It is possible to define a different implementation for a template when a specific type is passed as template argument. This is called a template specialization.
For example, let's suppose that we have a very simple class called mycontainer that can store one element of any type and that has just one member function called increase, which increases its value. But we find that when it stores an element of type char it would be more convenient to have a completely different implementation with a function member uppercase, so we decide to declare a class template specialization for that type:
Example ; -
// template specialization
#include < iostream >
using namespace std;
// class template:
template
class mycontainer {
T element;
public:
mycontainer (T arg) {element=arg;}
T increase () {return ++element;}
};
// class template specialization:
template <>
class mycontainer {
char element;
public:
mycontainer (char arg) {element=arg;}
char uppercase ()
{
if ((element>='a')&&(element<='z'))
element+='A'-'a';
return element;
}
};
int main () {
mycontainer myint (7);
mycontainer mychar ('j');
cout << myint.increase() << endl;
cout << mychar.uppercase() << endl;
return 0;
}
Variadic templates
C++11 introduced variadic templates, which can take a variable number of arguments in a manner somewhat similar to variadic functions such as std::printf. Both function templates and class templates can be variadic.
Template V/s Macros
Both macros and templates are expanded at compile time. Macros are always expanded inline, while templates are only expanded inline when the compiler deems it appropriate. When expanded inline, macro functions and function templates have no extraneous runtime overhead. Template functions with many lines of code will incur runtime overhead when they are not expanded inline, but the reduction in code size may help the code to load from disk more quickly or fit within RAM caches.
Templates are considered type-safe; that is, they require type-checking at compile time. Hence, the compiler can determine at compile time whether the type associated with a template definition can perform all of the functions required by that template definition.
By design, templates can be utilized in very complex problem spaces, whereas macros are substantially more limited.
Disadvantages of Templates
There are fundamental drawbacks to the use of templates:
1. Historically, some compilers exhibited poor support for templates. So, the use of templates could decrease code portability.
2. Many compilers lack clear instructions when they detect a template definition error. This can increase the effort of developing templates, and has prompted the development of Concepts for possible inclusion in a future C++ standard.
3. Since the compiler generates additional code for each template type, indiscriminate use of templates can lead to code bloat, resulting in larger executables.
4. Because a template by its nature exposes its implementation, injudicious use in large systems can lead to longer build times.
5. It can be difficult to debug code that is developed using templates. Since the compiler replaces the templates, it becomes difficult for the debugger to locate the code at runtime.
6. Templates of Templates (nesting) are not supported by all compilers, or might have a max nesting level.
7. Templates are in the headers, which require a complete rebuild of all project pieces when changes are made.
8. No information hiding. All code is exposed in the header file. No one library can solely contain the code.


Free Web Hosting