Compile-time polymorphism
(Also known as syntactic polymorphism and static polymorphism, contrast with runtime polymorphism.)
With template functions, one can write code that relies on type constructors and call signatures of families of parametrized types, without having to introduce a common base class.
In the book Elements of Programming, the authors refer to this treatment of types as abstract genera. With concepts one can specify the requirements on such type parameters, though C++ doesn't mandate such specifications.
Two simple examples:
#include
template
T twice(T n) {
return 2 * n;
}
InIt find(InIt f, InIt l,
typename std::iterator_traits::reference v)
{
while (f != l && *f != v)
++f;
return f;
}
int main(int argc, char* argv[]) {
if (6 != twice(3))
throw std::logic_error("3 x 2 = 6");
int const nums[] = { 1, 2, 3 };
if (nums + 4 != find(nums, nums + 4, 42))
throw std::logic_error("42 should not have been found.");
return 0;
}
One can call twice with any regular type that has a binary * operator defined. Similarly, one can call find() with any types that are comparable and that model Input Iterator. One set of code operates similarly on different types, with no shared base classes in sight.
Of course, what's really going on here is that it's the same source code being expanded into various type-specific functions at template instantiation time, each with separate generated machine code. Accommodating the same set of types without templates would have required either 1) separate hand-written functions with specific signatures, or 2) runtime polymorphism through virtual functions.