If you have an algorithm or function that can be expressed independent of the representation details of the arguments and without complicated case-by-case
variations, it should be written in a generic form. Thereby, instead of implementing a concrete function (or class), just a template for the function (or class)
is provided that is later filled with concrete realizations of types. This is called \emph{generic programming}.
\begin{zitat}{Musser, David R.; Stepanov, Alexander A., Generic Programming (1989)}
Generic programming centers around the idea of abstracting from concrete, efficient algorithms to obtain generic algorithms that can be combined with
different data representations to produce a wide variety of useful software.
Generic programming in C++ allows to parametrize functions and classes not just with values (function parameters, or constructor arguments), but with types.
A \emph{template parameter} thereby is a special kind of parameter passed to the function, class, or even variable. Inside of the realization of the function
or class, this type parameter, represented by its name, can be used as any other regular type, \eg to declare variables, to specify function parameter lists
or return types, or to parametrize other function or class templates.
An introductory example illustrates the usage of function and class templates:
\begin{minted}{c++}
#include <cmath>
// class template
template <typename T> // T is type for coordinates, e.g. T=double
struct MyPoint
{
using value_type = T; // introduction of a type alias
T x, y; // type T used here to declare a variable
// alternatively: value_type x,y;
};
// function template
template <typename P> // P is type for the vectors to calculate the distance of
auto distance(P const& a, P const& b) // type P in the argumentlist, both arguments
{ // should have the same type.
using T = typename P::value_type; // access to a class type
T dx = a.x - b.x;
T dy = a.y - b.y; // Or: auto dy = a.y - b.y
return std::sqrt(dx * dx + dy * dy);
}
\end{minted}
The call to the (generic) function \texttt{distance}, \ie the \emph{instantiation} of that function with a concrete type, is
initiated by passing concrete arguments to that function, or by specifying the type explicitly
\begin{minted}{c++}
int main()
{
// Type for MyPoint explicitly specified
MyPoint<double> a{1.0, 2.0}, b{7.0,-1.5};
// Or implicit deduction of the type (C++17)
MyPoint c{2.0, 3.0}; // double coordinates
MyPoint d{3.0f, 4.0f}; // float coordinates
// Type for the arguments of distance( , ) automatically deduced
std::cout << "Distance of a and b (double) = "
<< distance(a,b) << std::endl;
// Similarly, by explicit specification:
std::cout << "Distance of a and b (double) = "
<< distance<MyPoint<double>>(a,b) << std::endl;
// Call the function with different type
MyPoint<float> a2{1.0f, 2.0f}, b2{7.0f,-1.5f};
std::cout << "Distance of a and b (float) = "
<< distance(a2,b2) << std::endl;
// invalid argument types
distance(1.0, 2.0); // ERROR: `double` has no `value_type` and access to
// the members x and y not possible
// incompatible argument types MyPoint<double> and MyPoint<float>
It simply starts with the keyword \texttt{template} and in angular brackets \texttt{<...>} a comma separated list of template parameters.
The argument \texttt{NAMEx} is called \emph{template parameter} and must be a valid name in C++. The argument is introduced with either the
additional keyword \texttt{typename} or \texttt{class} for type-parameters (there is no difference of these two keywords).
\begin{rem}
Also, \texttt{NAME} can be a \emph{nontype}-parameter, a \emph{template}-parameter, or a \emph{parameter-pack}. We will focus here on type parameters and later introduce nontype parameters.
\end{rem}
\begin{rem}
The number of template parameters is restricted only by compiler-specific limits.
\end{rem}
The call of a function template is a two-phase procedure:
\begin{enumerate}
\item Template instantiation $\rightarrow$ concrete function
\item Invocation of that concrete function
\end{enumerate}
\emph{Template instantiation} is the process of filling the placeholder template parameters with concrete types (or values, see below). This can be achieved
in two ways. 1. Explicit specification of the types:
%
\cppline{FUNCTION_NAME<TYPES...>(PARAMETERS);}
%
where \texttt{TYPES} must be replaced with concrete types in the order of the template parameter declaration (without the keywords \texttt{typename} or
\texttt{class}).
Or the template instantiation can be obtained by implicit deduction of the template parameter types from the function arguments
(\emph{argument type deduction} (ATD)):
%
\cppline{FUNCTION_NAME(PARAMETERS);}
%
Thereby, the function parameter must be dependent on all the template parameter types.
\begin{example}
We have the function template \texttt{abs\_difference} defined as follow:
\begin{minted}{c++}
template <typename T>
T abs_difference(T value1, T value2)
{
return std::abs(value1 - value2);
}
\end{minted}
Explicit instantiation of this function template:
\begin{minted}{c++}
abs_difference<double>(1.0, 2.0);
abs_difference<float>(1.0f, 2.0f);
\end{minted}
and implicit instantiation by argument type deduction:
\begin{minted}{c++}
abs_difference(1.0, 2.0); // -> T = double
abs_difference(3, 4); // -> T = int
\end{minted}
\end{example}
The type deduction thereby is very similar to the \cpp{auto} type deduction from the auto-placeholder syntax introduced before.
Actually, in C++ first the template parameter deduction was invented and later the auto-type deduction was added with \cxx{11}.
\begin{rem}
Argument type deduction only works if all the types can be deduced uniquely from the function parameters. In the example above, we have
declared a function template with two parameters and have specified both with the same template parameter \texttt{T}. Thus, we have to
pass two arguments of the same type to the function template in order to allow the template parameters to be deduced from the
The parameter \texttt{T} could be either deduced to \cpp{double} or to \cpp{float}.
But, if the template is instantiated with an explicit type, no automatic deduction needs to be done and thus we have a regular
function that can be called with different argument that are automatically converted:
%
\begin{minted}{c++}
abs_difference<double>(a, b); // OK => generates function 'double(double,double)' and
// calls this function with parameters double and float
// -> implicit conversion of float to double
\end{minted}
\end{rem}
Since function templates can be ``called'' like regular functions, name and overload resolution must be considered. This will be discussed in detail
later. Here just an example:
\begin{minted}{c++}
// non-template function
double abs_difference(double a, double b); // (a)
// function template
template <class T>
T abs_difference(T a, T b); // (b)
double a=1.0, b=2.0;
abs_difference(a,b); // (1) calls (a)
abs_difference<double>(a,b); // (2) calls (b)
abs_difference<>(a,b); // (3) calls (b)
\end{minted}
If there is an exact match of a non-templated function, this is always preferred (1). If the explicit instantiation with empty template parameter list,
it asks for argument type deduction, but enforces a call to the instantiated template, instead of the non-template (3).
We call this a \emph{template declaration} (or \emph{template definition} in case of class definition) with \texttt{NAMEx} the \emph{template parameters}.
\texttt{CLASS\_DECLARATION} is thereby either \cpp{struct CLASS_NAME} or \cpp{class CLASS_NAME} (similar to regular classes).
Again, there is no difference between \texttt{typename} and \texttt{class} of the template parameter declaration, for type parameters.
\begin{rem}
In analogy to function parameters, template parameters can have default ``values'' (or default types), specified starting from the right-most template
parameter:
\cppline{template <class T1, class T2, class T3 = int> class CLASS_NAME { ... };}
\end{rem}
The \emph{template instantiation} of a class template, \ie the replacement of a template parameter with a concrete type (or value), follows the syntax
Not all types are allowed as non-type template parameters. It must be possible to uniquely evaluate those types at compile-type. Therefore the C++
standard has restricted non-type template parameters to integral types, enums, characters, and pointer types (until C++17) and floating-point types and some literal class types (since C++20).
\end{rem}
Similar to type parameters, default values are possible:
\begin{minted}{c++}
template <class T, int N = 3>
struct fixed_size_array { ... };
\end{minted}
Since non-type parameters must be specified at compile-time to instantiate that template, it must be a \cpp{constexpr}. Runtime values are not allowed:
\begin{minted}{c++}
constexpr int n = 7;
fixed_size_array<double, n> point7D; // OK
int m = 5;
fixed_size_array<double, m> point5D; // ERROR: m is runtime value
A Functor is an abstraction of a classical function, but implemented as class type. It can be used (called) like a regular function, but has additional
advantage to use all the flexibility of a class, like local member variables, or other member functions that can be called.
The basic idea is, that a class that implements the \cpp{operator()} can be evaluated like a function. The call to that special member function has the same
syntax as a regular function invocation.
Example:
\begin{minted}{c++}
struct Square {
// Implementation of the bracket operator
double operator()(double x) const {
return x*x;
}
};
int main() {
// Instantiation of the class
Square square{};
// Use the instance of the class, like a regular function
double y = square(3.0); // = 9
}
\end{minted}
\begin{guideline}{Guideline}
Implement functors as classes with an overloaded \cpp{operator()} as \cpp{public} and (often) \cpp{const} member-function.
We could even instantiate the functor directly in the call of the \cpp{for_each} function, \ie
\cppline{for_each(v, Square{});}
The problem with this approach is, that we might want to pass different functors to the same function / algorithm. This is a perfect example
of a function template. Instead of explicitly specifying the type of the functor that we can pass, we specify a template parameter for the functor
argument:
\begin{minted}{c++}
template <class F>
void for_each(std::vector<double>& vec, F const& f) {
for (auto& v_i : vec)
v_i = f(v_i);
}
\end{minted}
This allows to call the function \cpp{for_each} the same way as before (thanks to ATD), but we can also pass another functor without reimplementing the
algorithm.
\begin{rem}
A more generic implementation of the \cpp{for_each} function uses a second template parameter for the container type, \ie
%
\begin{minted}{c++}
template <class Range, class F>
void for_each(Range& range, F const& f) {
for (auto& element : range)
element = f(element);
}
\end{minted}
%
This allows to use that function with \cpp{std::vector<...>} of any type supported by the functor, or \cpp{std::list}, \cpp{std::array}, or
any other type that can be iterated over using range-based for-loops.
In \marginpar{[\cxx{11}]}\cxx{11} the definition of functors was simplified a lot. Instead of writing a class or class template first, then instantiating that
class and passing it to an algorithm, one can define an ``anonymous'' functor directly in the line of usage. The compiler then generates automatically
a corresponding class with a unique names, instantiates that class and passes it to the function.
Those anonymous functors are called \emph{lambda expressions} in C++ and can be declared as follows:
%
\begin{minted}{c++}
[captures...] (parameters...) -> ReturnType { function body };
/* or shorted in case of empty parameter list */
[captures...] { function body };
\end{minted}
%
Without the \emph{capture} clause, it looks like a regular function definition.
\begin{itemize}
\item The \emph{captures} is a list of zero or more variables or references that can be used inside the function.
\item\emph{parameters} is a list of function parameters including its types and qualifiers (like in regular function declarations)
\item\emph{ReturnType} is the (optional) (trailing) return type of the function, that can depend on the types of the function parameters
It can be omitted, resulting in the automatic return type deduction, like in functions returning \cpp{auto}.
\item The function body may contain any sequence of C++ statements and (optionally) a return statement.
\end{itemize}
\begin{example}
The following example illustrates the usage of lambda expressions, compared to classical functors:
\begin{minted}{c++}
// functor with internal member variable to store data.
struct Scale {
double factor_;
Scale(double factor = 1.0)
: factor_(factor)
{}
double operator()(double value) const
{
return value * factor_;
}
};
int main() {
std::vector<double> v = {1.0, 2.0, 3.0, 4.0, 5.0};
double factor = 3.0;
// Instantiate a regular functor with constructor argument
Since \marginpar{[\cxx{20}]}\cxx{20}, a similar syntax as used for generic lambda can be used for regular function. When placeholder types \cpp{auto} appear in the
parameter list of a function declaration or of a function template declaration, the declaration declares a function template, and one
invented template parameter for each placeholder is appended to the template parameter list.
%
\begin{minted}{c++}
void f1(auto arg); // same as template<class T> void f1(T arg)
void f2(auto const& arg); // same as template<class T> void f2(T const& arg)
\end{minted}
%
This is especially useful if the actual type of the argument is irrelevant but the algorithm allows to generically pass arguments of different
A central layer of abstraction introduced in the C++ standard library are \emph{iterators}. Frankly, iterators are objects allowing the
programmer to traverse the elements of an arbitrary container, without knowing the specific implementation, the data storage or the access pattern to
individual elements of that data-structure. While vectors and arrays may have a direct element access, using the \cpp{operator[]}, lists and trees do
not have such a method, or it might be very expensive to retrieve a specific element in the sequence rather than traversing linearly through the container.
An abstraction that you find in C and that is often that case of an implementation of a data-structure are pointers, pointing to the individual elements or
to the next and previous element in a sequence. But it is not required that containers are implemented with a chain of pointers and constructing the pointer
to an element could be an additional operation. Also, pointers do not give me any information about how a sequence might be traversed and where to find the
next element.
The abstraction that we want to discuss here are \emph{iterators}. They provide similar semantics as regular pointers, but incrementing (or decrementing)
an iterator means pointing to the next (previous) element in the sequence rather than the next position in memory. To allow iterators to be used similar to
pointers, they provide at least the following operation:
\begin{itemize}
\item Dereferencing with \cpp{operator*}, to access the element the iterator is pointing to
\item Going to the next element in the sequence, be pre or post increment \cpp{operator++}
\item Test for equality and inequality by \cpp{operator==} and \cpp{operator!=}.
\end{itemize}
Additionally, iterators are light-weight objects, meaning: they can be copied and returned/passed by value without much overhead. They have a size similar
\section{Iterators of standard library containers}
In the standard library, all containers (\eg\cpp{std::vector}, \cpp{std::list}, \cpp{std::set}) provide at least two functions, \cpp{begin()} and \cpp{end()}
returning an iterator object. Thereby, \cpp{begin()} points to the first element in the sequence and \cpp{end()} is a so called \emph{sentinel} -- an abstraction of a past-the-end iterator.