Generic programming: Difference between revisions

Content deleted Content added
Tags: Mobile edit Mobile web edit
Tags: Mobile edit Mobile web edit
 
(3 intermediate revisions by the same user not shown)
Line 213:
 
=====Technical overview=====
There are many kinds of templates, the most common being function templates and class templates. A ''function template'' is a pattern for creating ordinary functions based upon the parameterizing types supplied when instantiated. For example, the C++ Standard Template Library contains the function template <code>std::max(x, y)</code> that creates functions that return either ''x'' or ''y,'' whichever is larger. <code>max()</code> could be defined like this:
 
<syntaxhighlight lang="cpp">
Line 238:
</syntaxhighlight>
 
This works whether the arguments <code>x</code> and <code>y</code> are integers, strings, or any other type for which the expression <code>x &lt;< y</code> is sensible, or more specifically, for any type for which <code>operator&lt;</code> is defined. Common inheritance is not needed for the set of types that can be used, and so it is very similar to [[Duck typing#Templates or generic types|duck typing]]. A program defining a custom data type can use [[operator overloading]] to define the meaning of <code>&lt;<</code> for that type, thus allowing its use with the <code>std::max()</code> function template. While this may seem a minor benefit in this isolated example, in the context of a comprehensive library like the STL it allows the programmer to get extensive functionality for a new data type, just by defining a few operators for it. Merely defining <code>&lt;<</code> allows a type to be used with the standard <code>std::sort()</code>, <code>std::stable_sort()</code>, and <code>std::binary_search()</code> algorithms or to be put inside data structures such as <code>std::set</code>s (equivalent to <code>TreeSet</code>, [[heap (programming)|heap]]s, and [[associative array]]s.
 
C++ templates are completely [[type safe]] at compile time. As a demonstration, the standard type <code>std::complex</code> does not define the <code>&lt;<</code> operator, because there is no strict order on [[complex number]]s. Therefore, <code>std::max(x, y)</code> will fail with a compile error, if ''x'' and ''y'' are <code>complex</code> values. Likewise, other templates that rely on <code>&lt;<</code> cannot be applied to <code>complex</code> data unless a comparison (in the form of a functor or function) is provided. E.g.:For Ainstance, <code>std::complex</code> cannot be used as key for a <code>std::map</code> (equivalent to <code>TreeMap</code>) unless a comparison is provided. Unfortunately, compilers historically generate somewhat esoteric, long, and unhelpful error messages for this sort of error. Ensuring that a certain object adheres to a [[protocol (computer science)|method protocol]] can alleviate this issue. Languages which use <code>std::compare</code> instead of <code>&lt;<</code> can also use <code>std::complex</code> values as keys.
 
Another kind of template, a ''class template,'', extends the same concept to classes. A class template specialization is a class. Class templates are often used to make generic containers. For example, the STL has a [[doubly linked list]] container, <code>std::list</code> (equivalent to <code>LinkedList</code>). To make a linked list of integers, one writes <code>std::list&lt;<int&gt;></code>. A list of strings is denoted <code>std::list&lt;<std::string&gt;></code>. A <code>std::list</code> has a set of standard functions associated with it, that work for any compatible parameterizing types.
 
[[C++20]] introduces constraining template types using [[Concepts (C++)|concepts]]. Constraining the <code>max()</code> could look something like this:
 
<syntaxhighlight lang="cpp">
// in typename declaration:
template <std::totally_ordered T>
[[nodiscard]]
constexpr T max(T x, T y) noexcept {
return x < y ? y : x;
}
 
// in requires clause:
template <typename T>
requires std::totally_ordered<T>
[[nodiscard]]
constexpr T max(T x, T y) noexcept {
return x < y ? y : x;
}
</syntaxhighlight>
 
=====Template specialization=====
Line 698 ⟶ 717:
typeof (b) _b = (b); \
_a > _b ? _a : _b; })</syntaxhighlight>
 
The keyword <code>_Generic</code> is used in C preprocessor macros to automatically match the type of its parameter.
 
<syntaxhighlight lang="c">
#include <stdio.h>
 
#define type_of(x) _Generic((x), \
int: "int", \
float: "float", \
double: "double", \
char*: "string", \
default: "unknown")
 
int main(int argc, char* argv[]) {
printf("%s\n", type_of(42));
printf("%s\n", type_of(3.14f));
printf("%s\n", type_of(2.718));
printf("%s\n", type_of("hello"));
printf("%s\n", type_of((void *)0));
return 0;
}
</syntaxhighlight>
 
==See also==