<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  <meta http-equiv="Content-Style-Type" content="text/css" />
  <meta name="generator" content="pandoc" />
  <meta name="author" content="J. Monnon" />
  <meta name="date" content="2018-02-26" />
  <title>Type functions and beyond</title>
  <style type="text/css">code{white-space: pre;}</style>
  <style type="text/css">
table.sourceCode, tr.sourceCode, td.lineNumbers, td.sourceCode {
  margin: 0; padding: 0; vertical-align: baseline; border: none; }
table.sourceCode { width: 100%; line-height: 100%; }
td.lineNumbers { text-align: right; padding-right: 4px; padding-left: 4px; color: #aaaaaa; border-right: 1px solid #aaaaaa; }
td.sourceCode { padding-left: 5px; }
code > span.kw { color: #007020; font-weight: bold; }
code > span.dt { color: #902000; }
code > span.dv { color: #40a070; }
code > span.bn { color: #40a070; }
code > span.fl { color: #40a070; }
code > span.ch { color: #4070a0; }
code > span.st { color: #4070a0; }
code > span.co { color: #60a0b0; font-style: italic; }
code > span.ot { color: #007020; }
code > span.al { color: #ff0000; font-weight: bold; }
code > span.fu { color: #06287e; }
code > span.er { color: #ff0000; font-weight: bold; }
  </style>
</head>
<body>
<pre><code>Document Number: P0844R0
Date: 2018-02-26
Reply-to: J. Monnon (jmonnon@aldebaran.com)
Audience: EWG, SG7, SG8</code></pre>
<div id="header">
<h1 class="title">Type functions and beyond</h1>
<h1 class="subtitle">An exploration of type functions and concept functions</h1>
<h2 class="author">J. Monnon</h2>
<h3 class="date">2018-02-26</h3>
</div>
<div id="TOC">
<ul>
<li><a href="#i.-introduction">I. Introduction</a><ul>
<li><a href="#abstract">1. Abstract</a></li>
<li><a href="#terminology">2. Terminology</a></li>
<li><a href="#general-considerations">3. General considerations</a></li>
<li><a href="#design-rules">4. Design rules</a></li>
<li><a href="#constexpr-based-metaprogramming">5. <code>constexpr</code>-based metaprogramming</a></li>
</ul></li>
<li><a href="#ii.-type-functions">II. Type functions</a><ul>
<li><a href="#type-traits-as-functions">1. Type traits as functions</a></li>
<li><a href="#overloading">2. Overloading</a></li>
<li><a href="#concepts-introducing-types">3. Concepts introducing types</a></li>
<li><a href="#overloading-continued">4. Overloading (continued)</a></li>
<li><a href="#conditionals-with-if">5. Conditionals with <code>if</code></a></li>
<li><a href="#pattern-matching-with-switch-case">6. Pattern-matching with <code>switch case</code></a></li>
<li><a href="#processing-sequence-of-types-with-for">7. Processing sequence of types with <code>for</code></a></li>
<li><a href="#adl">8. ADL</a></li>
<li><a href="#composition">9. Composition</a></li>
<li><a href="#operator-overloading">10. Operator overloading</a><ul>
<li><a href="#a.-comparison-operators">a. Comparison operators</a></li>
<li><a href="#b.-relational-operators">b. Relational operators</a></li>
<li><a href="#c.-logical-operators">c. Logical operators</a></li>
<li><a href="#d.-composition-operator">d. Composition operator</a></li>
<li><a href="#e.-sum-types-and-product-types">e. Sum types and product types</a></li>
</ul></li>
<li><a href="#metaclasses">11. Metaclasses</a><ul>
<li><a href="#a.-metaclasses-as-type-functions">a. Metaclasses as type functions</a></li>
<li><a href="#b.-.is">b. <code>.is</code></a></li>
<li><a href="#c.-.as">c. <code>.as</code></a></li>
</ul></li>
<li><a href="#type-attributes-and-type-constructors">12. Type attributes and type constructors</a><ul>
<li><a href="#a.-type-attributes">a. Type attributes</a></li>
<li><a href="#b.-type-constructors">b. Type constructors</a></li>
</ul></li>
<li><a href="#note-on-the-implementation">13. Note on the implementation</a></li>
</ul></li>
<li><a href="#iii.-concept-functions">III. Concept functions</a><ul>
<li><a href="#optional-and-composition">1. Optional() and composition</a></li>
<li><a href="#instrumented">2. Instrumented</a></li>
</ul></li>
<li><a href="#iv.-further-considerations">IV. Further considerations</a><ul>
<li><a href="#opportunity-for-unification">1. Opportunity for unification</a></li>
<li><a href="#on-metaprogramming">2. On metaprogramming</a></li>
</ul></li>
<li><a href="#v.-acknowledgements">V. Acknowledgements</a></li>
<li><a href="#vi.-references">VI. References</a><ul>
<li><a href="#elements-of-programming">[Elements of Programming] Alexander Stepanov &amp; Paul McJones, 2009, Addison-Wesley</a></li>
<li><a href="#boost-hana">[Boost.Hana] Louis Dionne, <em>Hana</em></a></li>
<li><a href="#p0425">[P0425] Louis Dionne, <em>Metaprogramming by design, not by accident</em></a></li>
<li><a href="#p0707">[P0707] Herb Sutter, <em>Metaclasses: Generative C++</em></a></li>
<li><a href="#p0343">[P0343] Vicente J. Botet Escribá, <em>Meta-programming High-Order functions</em></a></li>
<li><a href="#cppreference">[cppreference.com] Constraints and concepts</a></li>
<li><a href="#p0694">[P0694] Bjarne Stroustrup, <em>Function declarations using concepts</em></a></li>
<li><a href="#p0095">[P0095] David Sankel, <em>Pattern Matching and Language Variants</em></a></li>
</ul></li>
</ul>
</div>
<h1 id="i.-introduction"><a href="#i.-introduction">I. Introduction</a></h1>
<h2 id="abstract"><a href="#abstract">1. Abstract</a></h2>
<p>This document proposes to extend functions to let them operate directly on types and concepts. The goal is to allow writing metaprogramming in the most intuitive and consistent way with the rest of the language.</p>
<p>Here is an example of a type function:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    ForwardIterator IteratorType(<span class="kw">typename</span> T) {
        <span class="co">// In a type function, an `if` behaves as a `if constexpr`.</span>
        <span class="kw">if</span> (Container(T))  <span class="co">// `Container` is a concept</span>
            <span class="kw">return</span> T::iterator;
        <span class="kw">else</span> <span class="kw">if</span> (Array(T)) <span class="co">// `Array` is a concept</span>
            <span class="kw">return</span> Decay(T);
    }

    <span class="co">// On call site:</span>
    <span class="kw">typename</span> I = IteratorType(C);</code></pre>
<p>A type function is always executed at compile-time. Here, it takes a type <code>T</code> and returns another type that models the <code>ForwardIterator</code> concept. Type functions allow a natural and straightforward notation to manipulate types.</p>
<p>They also allow to introduce powerful mechanisms, such as <code>switch case</code> to perform pattern-matching:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    <span class="co">// The codomain is the return type of a mathematical function type.</span>
    <span class="kw">typename</span> CodomainType(FunctionObject F) { <span class="co">// FunctionObject is a concept, F is a type</span>
        <span class="kw">typename</span> Ret; <span class="co">// We declare an unconstrained type</span>
        Class C;      <span class="co">// and a class type (`Class` is a concept)</span>
                      <span class="co">// for the following pattern matching:</span>
        <span class="kw">switch</span> (F) {
        <span class="kw">case</span> Ret (...):                      <span class="co">// function</span>
        <span class="kw">case</span> Ret (*)(...):                   <span class="co">// pointer to function</span>
        <span class="kw">case</span> Ret (C::*)(...):                <span class="co">// pointer to member function</span>
        <span class="kw">case</span> Ret (C::*)(...) <span class="dt">const</span>:          <span class="co">// pointer to const member function</span>
        <span class="kw">case</span> Ret (C::*)(...) <span class="dt">volatile</span>:       <span class="co">// pointer to volatile member function</span>
        <span class="co">// other variants omitted...</span>
            <span class="kw">return</span> RemoveCv(RemoveReference(Ret));
        <span class="kw">default</span>:                             <span class="co">// user-defined type</span>
            ...
        }
    }</code></pre>
<p>This document proposes that the syntax <code>&lt;concept-name&gt; &lt;name&gt;</code> always introduces a type, and not an object (e.g. <code>ForwardIterator I</code> introduces the type <code>I</code>, with <code>I</code> having to model the concept <code>ForwardIterator</code>). The syntax <code>&lt;concept-name&gt;{&lt;type-name&gt;} &lt;name&gt;</code> is proposed to introduce an object whose type must model a given concept (e.g. <code>ForwardIterator{I} begin</code> introduces the object <code>begin</code> of type <code>I</code>, with <code>I</code> having to model the concept <code>ForwardIterator</code>).</p>
<p>This document also introduces usual function mechanisms for type functions : overloading, ADL and operator overloading.</p>
<p>For example with operator overloading, it is possible to compare two types with <code>==</code>:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    <span class="kw">typename</span> MyTypeFunction(FunctionObject F) {
        <span class="kw">if</span> (CodomainType(F) == <span class="dt">void</span>) {
            <span class="co">// special case...</span>
        } <span class="kw">else</span> {
            <span class="co">// ...</span>
        }
    }</code></pre>
<p>Some more advanced usages of operator overloading includes: <code>|</code> for composition ; <code>&amp;&amp;</code>, <code>||</code>, <code>!</code> for predicate types ; <code>+</code>, <code>*</code> for algebraic datatypes.</p>
<p>This is an example of a type function composition:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    <span class="co">// `RemoveCvReference`, `ValueType`, `CodomainType` are type functions.</span>
    <span class="co">// `CodomainOfValueType` is a new type function with `CodomainOfValueType(T)`</span>
    <span class="co">// begin equivalent to `CodomainType(ValueType(RemoveCvReference(T)))`.</span>
    <span class="kw">typename</span> CodomainOfValueType = RemoveCvReference | ValueType | CodomainType;

    <span class="co">// C is a container of function objects</span>
    <span class="kw">template</span>&lt;Container C&gt;
    <span class="dt">auto</span> do_stuff(C&amp;&amp; functions) {
        std::vector&lt;CodomainOfValueType(C)&gt; results;
        <span class="co">// ...</span>
    }</code></pre>
<p>A proposition is made to express <a href="#p0707">[P0707]</a>'s metaclasses in terms of type functions, as metaclasses seem to be a subset of type functions (which makes a priori this proposal an alternative and a superset of <a href="#p0707">[P0707]</a>'s metaclasses).</p>
<p>For that, a syntax <code>-&gt;(T) {...}</code> is introduced to inject code into a type <code>T</code>. The simplest example is for creating strong typedefs (equivalent to metaclass' <code>.as</code>):</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    <span class="kw">typename</span> new_type(<span class="kw">typename</span> T) {
        <span class="kw">return</span> -&gt;(T) {}; <span class="co">// injects nothing but creates a new type</span>
    }

    <span class="kw">typename</span> my_T = new_type(T);</code></pre>
<p>Type attributes (function associating a type to a compile-time object, such as <code>sizeof(T)</code>) are also considered as a variant of type functions, allowing for example to define <code>nameof(T)</code>, <code>membersof(T)</code>, and so on.</p>
<p>Finally, concept functions are introduced to manipulate and transform concepts. One of the simplest examples of concept function is to create a new concept by adding constraints to an existing one:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    <span class="co">// Adds the constraints of the `Serialize` concept to any concept.</span>
    concept Serializable(concept C) {
        <span class="kw">return</span> C &amp;&amp; Serialize;
    };

    <span class="co">// On call site:</span>
    <span class="kw">template</span>&lt;Serializable(Container) C&gt;
    ...

    <span class="co">// Or (assuming `Instrumented` is another concept function):</span>
    <span class="kw">template</span>&lt;Instrumented(Serializable(FunctionObject)) F&gt;
    ...</code></pre>
<p>For a greater readability, operators can also be used to compose concept functions:</p>
<pre><code>    concept InstrumentedSerializable = Serializable | Instrumented;

    // `InstrumentedSerializable(FunctionObject)` is now the same concept as
    // `Instrumented(Serializable(FunctionObject))`

    template&lt;InstrumentedSerializable(FunctionObject) F&gt;
    ...</code></pre>
<p>This document strives to show the consistency of its approach. The features it introduces can be grouped as:</p>
<ul>
<li>concepts introducing types only (not objects)</li>
<li>type functions</li>
<li>code injection variant (<code>-&gt;(T) {...}</code>)</li>
<li>concept functions</li>
</ul>
<h2 id="terminology"><a href="#terminology">2. Terminology</a></h2>
<p>A note on the terminology used in the rest of this document:</p>
<ul>
<li>&quot;concept&quot; means &quot;type-concept&quot;: a set of requirements on one or several types.</li>
<li>&quot;object&quot; means &quot;entity having a type&quot;, by opposition to a type itself (for example, in <code>int i</code>, <code>int</code> is a type and <code>i</code> is an object).</li>
</ul>
<h2 id="general-considerations"><a href="#general-considerations">3. General considerations</a></h2>
<p>As C++ programmers we typically think of functions as procedures operating on objects. In contrast, a mathematical function is more generally a rule associating to each element of a set (the domain) an element of another set (the codomain). As a rule, a mathematical function doesn't care about the nature of the associated elements. In particular, the level of abstraction of the elements is irrelevant.</p>
<p>In C++, when we write a metaprogram:</p>
<ul>
<li>we access <em>type attributes</em>, e.g.:
<ul>
<li>we access the size of a type with <code>sizeof(T)</code></li>
<li>we access the alignment of a type with <code>alignof(T)</code></li>
<li>we access the number of elements of a tuple with <code>std::tuple_size_v&lt;T&gt;</code></li>
</ul></li>
<li>we use <em>type functions</em> to associate a type to another type or to transform a type, e.g.:
<ul>
<li>we associate a container type to its iterator type</li>
<li>we decay an array type to a pointer type</li>
<li>we add members or add/delete methods to a type</li>
</ul></li>
<li>we use <em>type constructors</em> to create new types, e.g.:
<ul>
<li>we form a pointer type by appending <code>*</code> to an existing type</li>
<li>we form a vector type by instantiating the <code>std::vector</code> template class</li>
</ul></li>
</ul>
<p>(See <a href="#elements-of-programming">[Elements of Programming]</a>, section 1.7 for further information about this classification)</p>
<p>All these operations are mathematical functions that associate a type to something else. In the case of type attributes, the type is associated to a (compile-time) value. In the other cases, the type is associated to another type. The fact that these operations are pure mathematical functions is also confirmed by the purely functional nature of template metaprogramming.</p>
<p>Since these operations are functions, it is natural to denote them with the syntax of functions:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    codomain function(arg0, arg1...)</code></pre>
<p>The manipulated elements are not objects anymore, but types. Note that this is already the case with <code>sizeof(T)</code> and <code>alignof(T)</code>. The important point is not that elements have now a different nature (they are not objects anymore), it is rather that the manipulation pattern is the same (associating elements to other elements). That is, what is proposed here is to make the syntax emphasize the manipulation pattern rather than the nature of the manipulated elements (objects, types...).</p>
<p>This is intuitive and natural: this is what we do all day long by having our perceptions pattern-matching our environment. For example, we can recognize a circle on a road sign or we can express that the same arguments are used again and again in a discussion by saying this discussion goes in circle. We apply the same structural idea (circle) to elements of different natures (road sign, discussion). This is also a fundamental principle of mathematics: focusing on patterns, behaviors and relationships instead of the internal characteristics of the manipulated elements. This is what makes it general and powerful.</p>
<p>When designing C++, by focusing on patterns rather than the nature of the elements, we simplify the language, make it easier to learn, more consistent and more powerful. Every time we introduce a new entity (object, type, concept...) in the language, one of the questions should be &quot;how can we manipulate it?&quot; and &quot;how does it compose with the other features of the language?&quot;. Functions are precisely a good candidate as a manipulation tool because their main characteristic is composability (which is confirmed by a strong theoretical background). Moreover, users already master runtime functions and their features (overloading, ADL...) so the learning cost of extending functions to other entities such as types is minimal.</p>
<p>Of course, it must be noted that it is already possible to somewhat compose operations on types. For example with a cv-qualified integral type <code>N</code>, we can write:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    std::make_unsigned_t&lt;std::remove_cv_t&lt;N&gt;&gt; i = <span class="dv">0</span>;</code></pre>
<p>But these are functions in disguise and would be more naturally written as:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    MakeUnsigned(RemoveCv(N)) i = <span class="dv">0</span>;</code></pre>
<p>This is not only a syntax issue, using type functions allows us to depart from template metaprogramming constraints (instantiation cost, unnatural syntax) and reuse familiar runtime syntax to manipulate types (if, switch case, operators, etc.). This also allows us to reuse runtime function features, such as overloading and ADL (see <a href="#ii.-type-functions">section II</a>). From there, it is only natural to consider concept functions, because concepts are also entities to be manipulated by the users (see <a href="#iii.-concept-functions">section III</a>). Finally, homogenizing the syntax opens the door for future language unifications (e.g. functions able to indifferently operate on object or types, see <a href="#iv.-further-considerations">section IV</a>).</p>
<p>The goal of this document is to present the design of type functions and concept functions and show how they can change for the better programming in C++.</p>
<h2 id="design-rules"><a href="#design-rules">4. Design rules</a></h2>
<p>This document proposes introducing a new feature in the language, by trying to follow these design rules:</p>
<ul>
<li>to be orthogonal with other language features</li>
<li>to be composable</li>
<li>to focus on internal consistency</li>
<li>to be as simple and minimalistic as possible</li>
<li>to not artificially limit users' possibilities but to offer them a powerful tool they will freely use to solve their problems</li>
<li>to simplify the language by allowing to use similar constructs for similar patterns, whatever the abstraction layer</li>
<li>to strive for unification making the language simpler and more powerful</li>
<li>to not break existing language features</li>
</ul>
<h2 id="constexpr-based-metaprogramming"><a href="#constexpr-based-metaprogramming">5. <code>constexpr</code>-based metaprogramming</a></h2>
<p>Various approaches try to manipulate types as <code>constexpr</code> values. One such approach is <a href="#boost-hana">[Boost.Hana]</a> ; another one makes use of &quot;meta&quot; types to inspect types (<a href="#p0425">[P0425]</a>).</p>
<p>In both cases, the idea is to:</p>
<ol style="list-style-type: decimal">
<li>translate the type to a manipulable form (a <code>constexpr</code> object)</li>
<li>manipulate this form</li>
<li>translate back to a real type</li>
</ol>
<p>These approaches have their strengths: they leverage an existing mechanism (<code>constexpr</code> functions) to manipulate types. But they somewhat introduce a syntactic noise obfuscating the user's intent and do not syntactically acknowledge that on a logical level we are applying a function.</p>
<p>For instance, assuming the existence of a <code>constexpr</code> function <code>partial</code> that binds some type arguments to a function type, with <a href="#boost-hana">[Boost.Hana]</a> we write (this example is taken from <a href="#p0343">[P0343]</a>):</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    <span class="kw">typename</span> <span class="kw">decltype</span>(hana::partial(type_c&lt;Fn&gt;, type_c&lt;Args&gt;...))::type f;</code></pre>
<p>With <a href="#p0425">[P0425]</a>, the equivalent form is:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    TYPENAME(<span class="kw">decltype</span>(partial(REFLEXPR(Fn), REFLEXPR(Args)...))) f;</code></pre>
<p>where <code>REFLEXPR</code> yields the <code>constexpr</code> object for a type and <code>TYPENAME</code> translates back to a type.</p>
<p>We would prefer to simply write:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    Partial(Fn, Args...) f;</code></pre>
<p>where <code>Partial</code> is a type function, operating on types and yielding a type. <a href="#ii.-type-functions">Section II</a> shows how users can implement a type function. Some implementations might chose to translate type functions into template code, even if it might seem more natural to translate them into <code>constexpr</code> functions (see <a href="#note-on-the-implementation">section II. 13</a>).</p>
<h1 id="ii.-type-functions"><a href="#ii.-type-functions">II. Type functions</a></h1>
<p>This section introduces type functions: function manipulating types. This feature does not conflict with any language feature, except for an adaptation of how concepts introduce names (see <a href="#concepts-introducing-types">section II. 3</a>). In the following, type functions' features are introduced in an incremental way. Their main benefits may appear to the reader starting from <a href="#conditionals-with-if">section II. 5</a>.</p>
<h2 id="type-traits-as-functions"><a href="#type-traits-as-functions">1. Type traits as functions</a></h2>
<p>Consider a type trait that associates a type to its iterator type. Currently, we typically write this kind of code:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    <span class="co">// Default case: assume a container type.</span>
    <span class="kw">template</span>&lt;<span class="kw">typename</span> Container&gt;
    <span class="kw">struct</span> iterator_type {
        <span class="kw">using</span> type = <span class="kw">typename</span> Container::iterator;
    };

    <span class="co">// Array specialization.</span>
    <span class="kw">template</span>&lt;<span class="kw">typename</span> T, std::size_t N&gt;
    <span class="kw">struct</span> iterator_type&lt;T [N]&gt; {
        <span class="kw">using</span> type = T*;
    };</code></pre>
<p>And use it this way with a template type parameter <code>T</code>:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    <span class="co">// A `using` can be used to simplify the writing.</span>
    <span class="kw">typename</span> iterator_type&lt;T&gt;::type it;
    std::vector&lt;<span class="kw">typename</span> iterator_type&lt;T&gt;::type&gt; iters;</code></pre>
<p>This kind of traits are mathematical functions: they map an element to another one. The corresponding algorithm is:</p>
<pre><code>    For a type T,
    if T is an array of the form U [N]:
        return U*
    else
        return T's inner `iterator` typedef</code></pre>
<p>This algorithm is simple but currently translates in the language into a verbose and scattered implementation. The more complex the algorithm, the more problematic this situation is.</p>
<p>If we were not at compile-time but at runtime (let's say we write a dynamic type system), we would write something like:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    <span class="co">// `type` has all info about our dynamic type</span>
    type iterator_type(type t) {
        <span class="kw">if</span> (is_array(t))
            <span class="kw">return</span> decay_type(t);
        <span class="kw">else</span>
            <span class="kw">return</span> t.inner_type(<span class="st">&quot;iterator&quot;</span>);
    }</code></pre>
<p>We would like runtime version and compile-time versions to be as similar as possible (see next section).</p>
<h2 id="overloading"><a href="#overloading">2. Overloading</a></h2>
<p>Consider the following type function (implementation considerations can be found in <a href="#note-on-the-implementation">section II. 13</a>). We first handle the default case:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    <span class="co">// Default case: assume a container type.</span>
    ForwardIterator IteratorType(<span class="kw">typename</span> ContainerType) {
        <span class="kw">return</span> ContainerType::iterator;
    }</code></pre>
<p><code>IteratorType</code> is a function operating at compile-time on types. To specify that it operates on a type and not on an object (i.e. not on an instance of a type), the keyword <code>typename</code> is used. When the type itself is constrained, a concept is used.</p>
<p>Here, the type function takes an arbitrary type, i.e. a non-constrained type denoted by <code>typename</code>, and returns a type constrained by the <code>ForwardIterator</code> concept. Informally, we say that this type function takes any type and returns a forward iterator type.</p>
<p>Since a type function returns a type, it can be used wherever a type is allowed:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    <span class="co">// C is a container type.</span>
    IteratorType(C) it;
    std::vector&lt;IteratorType(C)&gt; iters;
    <span class="co">// etc.</span></code></pre>
<p>We now overload <code>IteratorType</code> for array types:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    <span class="co">// Array overload</span>
    RandomAccessIterator IteratorType(Array T)
    {
        <span class="kw">return</span> Decay(T);
    }</code></pre>
<p><code>Array</code> is a concept modeled by any native array type. It introduces a <em>type</em> and not an object (see <a href="#concepts-introducing-types">next section</a> for a discussion on this). <code>Decay</code> is another type function whose behavior is equivalent to <code>std::decay_t</code>.</p>
<p>It would be useful to be able to do a form of pattern-matching to decompose the array type <code>T</code> into <code>U[N]</code>. See <a href="#pattern-matching-with-switch-case">section II. 6</a> for more on this.</p>
<p>We now have two overloads but there is no ambiguity between them since the <code>Array</code> concept is more constrained than <code>typename</code> (no constraint).</p>
<p>Note that we could use an unconstrained concept in lieu of <code>typename</code>:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    <span class="kw">template</span>&lt;<span class="kw">typename</span> T&gt;
    concept AnyType = <span class="kw">true</span>;

    <span class="co">// Default case: assume a container type.</span>
    ForwardIterator IteratorType(AnyType ContainerType) {
        <span class="kw">return</span> ContainerType::iterator;
    }</code></pre>
<p>Also, this interface is a bit misleading since the default version won't work for any type but only on container types. This is addressed in <a href="#overloading-continued">section 4</a>.</p>
<h2 id="concepts-introducing-types"><a href="#concepts-introducing-types">3. Concepts introducing types</a></h2>
<p>The previous example conflicts with C++20 concepts, where <code>AnyType</code> for example would introduce an object and not a type. We think that in the same way as a type introduces an object, a concept should introduce a type:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    <span class="dt">int</span> i;
    <span class="co">// `i` is an object.</span>
    <span class="co">// The form of the declaration is: type object;</span>

    ForwardIterator I;
    <span class="co">// `I` is a type.</span>
    <span class="co">// The form of the declaration is: concept type;</span></code></pre>
<p>This would allow to keep a sane abstraction order (concept &gt; type &gt; object) by avoiding an &quot;abstraction jump&quot; from concept to object, which is logically unclear. This wouldn't impact other template parameters introduction, because they don't use concepts to introduce objects:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    <span class="co">// 'template introduction' syntax: ok</span>
    ForwardIterator{I}
    I algo_1(I begin, I end);

    <span class="co">// 'long form' syntax: ok</span>
    <span class="kw">template</span>&lt;ForwardIterator I, UnaryPredicate P&gt;
    I algo_2(I begin, I end, P predicate);</code></pre>
<p>Introducing types in a distinct way than objects also has the benefit to be unambiguous to the reader. Consider (taken from <a href="#cppreference">[cppreference.com]</a>):</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    <span class="dt">void</span> f0(Comparable a, Comparable* b);
    <span class="co">// The two `Comparable` introduce the same type.</span>
    <span class="co">// long form: template&lt;Comparable T&gt; void f0(T a, T* b);</span>

    <span class="dt">void</span> f1(<span class="dt">auto</span> a, <span class="dt">auto</span>* b);
    <span class="co">// The two `auto` introduce different types.</span>
    <span class="co">// long form: template&lt;typename T, typename U&gt; f1(T a, U* b);</span></code></pre>
<p>and compare them to this form, where information on concepts, types and objects is clearly stated:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    <span class="kw">template</span>&lt;ForwardIterator I0, ForwardIterator I1, UnaryPredicate P&gt;
    I1 algo_3(I0 begin0, I0 end0, I1 begin1, P predicate);</code></pre>
<p>One solution to have a concise and unambiguous syntax may be to allow the template introduction syntax in-place:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    ForwardIterator{I1} algo_3(ForwardIterator{I0} begin0, I0 end0,
                               I1 begin1, UnaryPredicate{P} predicate);

    <span class="co">// equivalent to the previous form:</span>

    <span class="kw">template</span>&lt;ForwardIterator I0, ForwardIterator I1, UnaryPredicate P&gt;
    I1 algo_3(I0 begin0, I0 end0, I1 begin1, P predicate);</code></pre>
<p>Note that <code>end0</code> and <code>begin1</code> are simply introduced by their respective types <code>I0</code> and <code>I1</code> without repetition of the concept. This solution is both concise, logically correct and non-ambiguous.</p>
<p>Also note that it is more concise, even compared to Stroustrup's &quot;natural syntax&quot; (see <a href="#p0694">[P0694]</a>):</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    <span class="co">// &quot;natural syntax&quot;</span>
    InputIterator find(InputIterator begin, InputIterator end, UnaryPredicate p);

    <span class="co">// proposed unambiguous syntax</span>
    InputIterator{I} find(I begin, I end, UnaryPredicate{P} p);</code></pre>
<p>Optionally, it could be allowed to omit naming the type when it is not needed:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    <span class="co">// No need to name the container type.</span>
    <span class="co">// Here, `container` is an object, not a type.</span>
    <span class="dt">void</span> algo_4(Container{}&amp; container);</code></pre>
<p>The same logic would apply on call site:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    <span class="co">// Introduces a forward iterator type `I`, and an object `it` of type `I`:</span>
    ForwardIterator{I} it = algo_1(begin(container), end(container));
    I tmp;
    <span class="co">// ...</span></code></pre>
<p>Or as before, if naming the type is not needed:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    ForwardIterator{} it = algo_1(begin(container), end(container));</code></pre>
<p>This is to contrast with the following, where <code>C</code> is a container type and <code>I</code> is a forward iterator type:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    <span class="co">// Here, `I` is a type.</span>
    ForwardIterator I = IteratorType(C);</code></pre>
<p>A clear distinction between objects (introduced only by types) and types (introduced only by concepts) is crucial to be able to manipulate types and define type functions as will be shown in the next sections.</p>
<h2 id="overloading-continued"><a href="#overloading-continued">4. Overloading (continued)</a></h2>
<p>Up to this point, we have used overloading to specialize our type functions for families of type (denoted by concepts). What if we want to specialize not for a family of types but for one specific type? We can notice that it can be done by using a concept matching our specific type only.</p>
<p>Going back to <code>IteratorType</code>, let's say we create a new type that has an associated iterator type, but that is neither a container type with an internal <code>iterator</code> typedef, nor an array. It could be an range adaptor, not owning its elements, and applying a transformation on the current value before dereferencing.</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    <span class="co">// Assumes `Range` and `Transformation` are concepts.</span>
    <span class="co">// A transformation is a function taking a value and</span>
    <span class="co">// returning another value of the same type.</span>
    <span class="kw">template</span>&lt;Range R, Transformation F&gt;
    <span class="kw">class</span> transformation_range;</code></pre>
<p>The iterator type we want to associate to <code>transformation_range</code> is:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    <span class="kw">template</span>&lt;Transformation F&gt;
    <span class="kw">class</span> transformation_iter;</code></pre>
<p>First, let's rewrite the default version of <code>IteratorType</code> to acknowledge that it effectively only accepts container types:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    ForwardIterator IteratorType(Container C) {
        <span class="kw">return</span> C::iterator;
    }</code></pre>
<p>Now we specialize <code>IteratorType</code> for our new type by assuming a <code>TransformationRange</code> concept only modeled by template instantiations of <code>transformation_range</code>:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    <span class="kw">template</span>&lt;<span class="kw">typename</span> T&gt;
    concept TransformationRange =
        ... <span class="co">// constraints</span>
    ;

    <span class="co">// We assume that `TransformationType` is a type function</span>
    <span class="co">// that returns the associated transformation type.</span>
    ForwardIterator IteratorType(TransformationRange T) {
        <span class="kw">return</span> transformation_iter&lt;TransformationType(T)&gt;;
    }</code></pre>
<p>It is fastidious to write a concept for a unique type (and to write associated type functions). As this case may often happen, we need a way to &quot;lift&quot; a type to the concept level. This means having a way to automatically generate, from a type, a concept modeled by this type only. We propose to do it with a <code>concept</code> built-in function:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    <span class="kw">template</span>&lt;Range R, Transformation F&gt;
    ForwardIterator IteratorType(concept(transformation_range&lt;R, F&gt;) T) {
        <span class="kw">return</span> transformation_iter&lt;F&gt;;
    }

    <span class="co">// or with in-place template introduction syntax:</span>
    ForwardIterator IteratorType(concept(transformation_range&lt;Range{R}, Transformation{F}&gt;) T) {
        <span class="kw">return</span> transformation_iter&lt;F&gt;;
    }</code></pre>
<p>With a type <code>X</code>, <code>concept(X)</code> returns a concept so in the example above <code>T</code> is a type, which non-ambiguously makes <code>IteratorType</code> a type function. This also allows to decompose a type by pattern-matching, in the same way it works with template specialization. In the example above, it allows us to access <code>F</code> without a <code>TransformationType</code> type function.</p>
<p>We can now call <code>IteratorType</code> on <code>transformation_range</code> template instantiations:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    <span class="co">// `Rng` is `transformation_range&lt;R, F&gt;`.</span>
    <span class="co">// `R` and `F` are deduced in `IteratorType`.</span>
    ForwardIterator I = IteratorType(Rng);</code></pre>
<h2 id="conditionals-with-if"><a href="#conditionals-with-if">5. Conditionals with <code>if</code></a></h2>
<p>Up to this point, we've seen overloading and one-line type functions. If we ignore the function syntax, this is very close to template specialization. Of course, the benefit of functions is shown by more complex examples. Type functions are an opportunity to introduce a more natural syntax for manipulating types.</p>
<p>We previously implemented the <code>IteratorType</code> trait with an overloaded type function. But we can also implement the default version as a single type function:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    ForwardIterator IteratorType(<span class="kw">typename</span> T) {
        <span class="kw">if</span> (Container(T))  <span class="co">// `Container` is a concept</span>
            <span class="kw">return</span> T::iterator;
        <span class="kw">else</span> <span class="kw">if</span> (Array(T)) <span class="co">// `Array` is a concept</span>
            <span class="kw">return</span> Decay(T);
        fail(<span class="st">&quot;T is neither a container type nor an array type.&quot;</span>);
    }</code></pre>
<p>We propose that a concept can be used as a type predicate. It returns <code>true</code> if the type fulfills all the requirements. Thus</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    Container(T)</code></pre>
<p>is equivalent to the current syntax</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    Container&lt;T&gt;()</code></pre>
<p>In a type function, all <code>if</code> are <code>constexpr</code>: a branch is evaluated only if the corresponding condition is true. In the previous example, if <code>T</code> is an <code>Array</code> the &quot;container&quot; branch is not evaluated, which avoids the ill-formed expression <code>T::iterator</code>. This behavior is intuitive and consistent with the behavior of runtime <code>if</code>.</p>
<p>We propose that the function <code>fail()</code> (naming subject to change) causes a classical &quot;substitution failure&quot;, so that the following function</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    <span class="kw">template</span>&lt;<span class="kw">typename</span> C&gt;
    IteratorType(C) f(C&amp; c, IteratorType(C) it);</code></pre>
<p>is discarded from the overload set if <code>IteratorType</code> fails, possibly displaying the failure message in verbose compilation.</p>
<p>Note: Having a centralized default version doesn't make specialization useless. Users still need to specialize for their types and concepts, as seen with <code>transformation_range</code>.</p>
<p>More complex uses of conditionals will be shown in the following sections.</p>
<h2 id="pattern-matching-with-switch-case"><a href="#pattern-matching-with-switch-case">6. Pattern-matching with <code>switch case</code></a></h2>
<p>Classical template metaprogramming relies on a limited form of pattern-matching: decomposing a type according to the different ways it can be created (pointer, array, function, etc.). For types <code>T</code>, <code>U</code>, <code>C</code> and integral constant <code>N</code>, this includes: <code>T*</code>, <code>T&amp;</code>, <code>T[N]</code>, <code>T(U)</code>, <code>T (C::*)(U)</code>, etc.</p>
<p>Functional programming languages make a heavy use of pattern matching through constructions similar to <code>switch case</code>.</p>
<p>We define <code>switch case</code> in type functions as a mechanism to perform pattern-matching. Let's rewrite <code>IteratorType</code> by leveraging this feature:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    ForwardIterator IteratorType(<span class="kw">typename</span> T) {
        <span class="kw">if</span> (Container(T))
            <span class="kw">return</span> T::iterator;
        <span class="kw">typename</span> U;    <span class="co">// declare an unconstrained type,</span>
        std::size_t N; <span class="co">// declare an integral constant</span>
                       <span class="co">// for the following pattern-matching:</span>
        <span class="kw">switch</span> (T) {
        <span class="kw">case</span> U[N]:
            <span class="kw">return</span> U*;
        <span class="kw">default</span>:
            fail(<span class="st">&quot;T is neither a container type nor an array type.&quot;</span>);
        }
    }</code></pre>
<p>Or by using in-place template introduction syntax:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    ForwardIterator IteratorType(<span class="kw">typename</span> T) {
        <span class="kw">if</span> (Container(T))
            <span class="kw">return</span> T::iterator;
        std::size_t N;
        <span class="kw">switch</span> (T) {
        <span class="kw">case</span> <span class="kw">typename</span>{U}[N]:
            <span class="kw">return</span> U*;
        <span class="kw">default</span>:
            fail(<span class="st">&quot;T is neither a container type nor an array type.&quot;</span>);
        }
    }</code></pre>
<p>The pattern-matching in the above example is useful but is more interesting in a more complex example. Let's define a codomain type function (the codomain is the return type of a mathematical function).</p>
<p>The algorithm is:</p>
<pre><code>    For a function object type F,
    if F is a native function type, pointer to function type or pointer to member function type
        return the codomain type obtained by pattern-matching
    else if F has an inner `codomain` typedef
        return it
    else if F has a unique (non-overloaded, non-template) `operator()`
        return the codomain type obtained by pattern-matching the corresponding
            pointer-to-member function type
    else
        fail</code></pre>
<p>Note that for this algorithm to succeed, the function object type must correspond a single mathematical function. That is, it must be associated with a specific domain (argument types) and a specific codomain (return type). This excludes function objects types that correspond to a family of mathematical functions, such as user-defined function object types whose <code>operator()</code> is overloaded or template.</p>
<p>Here is an implementation with a type function:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    <span class="kw">typename</span> CodomainType(FunctionObject F) { <span class="co">// FunctionObject is a concept</span>
        <span class="kw">typename</span> Ret; <span class="co">// We declare an unconstrained type</span>
        Class C;      <span class="co">// and a class type (`Class` is a concept)</span>
                      <span class="co">// for the following pattern matching:</span>
        <span class="kw">switch</span> (F) {
        <span class="kw">case</span> Ret (...):                      <span class="co">// function</span>
        <span class="kw">case</span> Ret (*)(...):                   <span class="co">// pointer to function</span>
        <span class="kw">case</span> Ret (C::*)(...):                <span class="co">// pointer to member function</span>
        <span class="kw">case</span> Ret (C::*)(...) <span class="dt">const</span>:          <span class="co">// pointer to const member function</span>
        <span class="kw">case</span> Ret (C::*)(...) <span class="dt">volatile</span>:       <span class="co">// pointer to volatile member function</span>
        <span class="kw">case</span> Ret (C::*)(...) <span class="dt">const</span> <span class="dt">volatile</span>: <span class="co">// pointer to const volatile member function</span>
                                             <span class="co">// lvalue-ref, rvalue-ref, noexcept variants omitted.</span>
            <span class="kw">return</span> RemoveCv(RemoveReference(Ret));
        <span class="kw">default</span>:                             <span class="co">// user-defined type</span>
            <span class="co">// If there is a `codomain` inner typedef, return it.</span>
            <span class="kw">if</span> (requires { <span class="kw">typename</span> F::codomain; }) {
                <span class="kw">return</span> F::codomain;
            }
            <span class="co">// Otherwise try to get a pointer to `operator()`.</span>
            <span class="kw">else</span> <span class="kw">if</span> (requires { &amp;F::<span class="kw">operator</span>(); }) {
                <span class="kw">return</span> CodomainType(<span class="kw">decltype</span>(&amp;F::<span class="kw">operator</span>()));
            }
            fail(<span class="st">&quot;operator() must not be overloaded or template.&quot;</span>);
        }
    }</code></pre>
<p>This example shows how pattern-matching, concepts, <code>requires</code> clause and <code>if</code> play nicely together in the context of type functions.</p>
<p>It is particularly useful to be able to regroup cases, in contrast to having an implementation scattered over multiple overloads.</p>
<p>This implementation shows that type functions allow a good expressivity, especially compared to the following C++17 metaprogramming equivalent:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    <span class="kw">template</span>&lt;<span class="kw">typename</span> T&gt;
    <span class="kw">class</span> has_nested_codomain_type {
        <span class="kw">template</span>&lt;<span class="kw">typename</span> U&gt;
        <span class="dt">static</span> std::true_type test(<span class="kw">typename</span> U::codomain_type*);

        <span class="kw">template</span>&lt;<span class="kw">typename</span>&gt;
        <span class="dt">static</span> std::false_type test(...);
    <span class="kw">public</span>:
        <span class="kw">using</span> type = <span class="kw">decltype</span>(test&lt;T&gt;(<span class="kw">nullptr</span>));
    };

    <span class="kw">template</span>&lt;<span class="kw">typename</span> T&gt;
    <span class="kw">using</span> has_nested_codomain_type_t = <span class="kw">typename</span> has_nested_codomain_type&lt;T&gt;::type;

    <span class="kw">template</span>&lt;<span class="kw">typename</span> T&gt;
    <span class="kw">struct</span> codomain_transform_arg : std::decay&lt;T&gt; {};

    <span class="kw">template</span>&lt;<span class="kw">typename</span> T&gt;
    <span class="kw">struct</span> codomain_class_pointer_helper;

    <span class="kw">template</span>&lt;<span class="kw">typename</span> Ret, <span class="kw">typename</span> C, <span class="kw">typename</span>... T&gt;
    <span class="kw">struct</span> codomain_class_pointer_helper&lt;Ret (C::*)(T...)&gt;
        : codomain_transform_arg&lt;Ret&gt; {};

    <span class="kw">template</span>&lt;<span class="kw">typename</span> Ret, <span class="kw">typename</span> C, <span class="kw">typename</span>... T&gt;
    <span class="kw">struct</span> codomain_class_pointer_helper&lt;Ret (C::*)(T...) <span class="dt">const</span>&gt;
        : codomain_transform_arg&lt;Ret&gt; {};

    <span class="kw">template</span>&lt;<span class="kw">typename</span> Ret, <span class="kw">typename</span> C, <span class="kw">typename</span>... T&gt;
    <span class="kw">struct</span> codomain_class_pointer_helper&lt;Ret (C::*)(T...) <span class="dt">volatile</span>&gt;
        : codomain_transform_arg&lt;Ret&gt; {};

    <span class="kw">template</span>&lt;<span class="kw">typename</span> Ret, <span class="kw">typename</span> C, <span class="kw">typename</span>... T&gt;
    <span class="kw">struct</span> codomain_class_pointer_helper&lt;Ret (C::*)(T...) <span class="dt">const</span> <span class="dt">volatile</span>&gt;
        : codomain_transform_arg&lt;Ret&gt; {};

    <span class="kw">template</span>&lt;<span class="kw">typename</span> T&gt;
    <span class="kw">struct</span> codomain_class_pointer : codomain_class_pointer_helper&lt;<span class="kw">decltype</span>(&amp;T::<span class="kw">operator</span>())&gt; {};

    <span class="kw">template</span>&lt;<span class="kw">typename</span> T, <span class="kw">typename</span> HasNestedCodomainType&gt;
    <span class="kw">struct</span> codomain_class_dispatch {
        <span class="kw">using</span> type = <span class="kw">typename</span> T::codomain_type;
    };

    <span class="kw">template</span>&lt;<span class="kw">typename</span> T&gt;
    <span class="kw">struct</span> codomain_class_dispatch&lt;T, std::false_type&gt; : codomain_class_pointer&lt;T&gt; {};

    <span class="kw">template</span>&lt;<span class="kw">typename</span> T&gt;
    <span class="kw">struct</span> codomain_class : codomain_class_dispatch&lt;T, has_nested_codomain_type_t&lt;T&gt;&gt; {};

    <span class="kw">template</span>&lt;<span class="kw">typename</span> T&gt;
    <span class="kw">struct</span> codomain_function;

    <span class="kw">template</span>&lt;<span class="kw">typename</span> Ret, <span class="kw">typename</span> ...T&gt;
    <span class="kw">struct</span> codomain_function&lt;Ret (T...)&gt; : codomain_transform_arg&lt;Ret&gt; {};

    <span class="kw">template</span>&lt;<span class="kw">typename</span> Ret, <span class="kw">typename</span> ...T&gt;
    <span class="kw">struct</span> codomain_function&lt;Ret (*)(T...)&gt; : codomain_transform_arg&lt;Ret&gt; {};

    <span class="kw">template</span>&lt;<span class="kw">typename</span> F, <span class="kw">typename</span> IsClass&gt;
    <span class="kw">struct</span> codomain_dispatch : codomain_class&lt;F&gt; {};

    <span class="kw">template</span>&lt;<span class="kw">typename</span> F&gt;
    <span class="kw">struct</span> codomain_dispatch&lt;F, std::false_type&gt; : codomain_function&lt;F&gt; {};

    <span class="kw">template</span>&lt;<span class="kw">typename</span> F&gt;
    <span class="kw">struct</span> codomain_type : codomain_dispatch&lt;F, <span class="kw">typename</span> std::is_class&lt;F&gt;::type&gt; {};

    <span class="kw">template</span>&lt;<span class="kw">typename</span> F&gt;
    <span class="kw">using</span> CodomainType = <span class="kw">typename</span> codomain_type&lt;F&gt;::type;</code></pre>
<p>We used <code>RemoveReference</code> in <code>CodomainType</code>. Its implementation can also be a good example of pattern-matching:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    <span class="kw">typename</span> RemoveReference(<span class="kw">typename</span> T) {
        <span class="kw">typename</span> U;
        <span class="kw">switch</span> (T) {
        <span class="kw">case</span> U&amp;:
        <span class="kw">case</span> U&amp;&amp;:
            <span class="kw">return</span> U;
        <span class="kw">default</span>:
            <span class="kw">return</span> T;
        }
    }</code></pre>
<p>Finally, in <code>CodomainType</code> we saw an example of type function &quot;chaining&quot;:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    RemoveCv(RemoveReference(Ret))</code></pre>
<p>We will see in <a href="#composition">section 9</a> how to easily compose functions.</p>
<h2 id="processing-sequence-of-types-with-for"><a href="#processing-sequence-of-types-with-for">7. Processing sequence of types with <code>for</code></a></h2>
<p>Up to this point, we've seen overloaded type functions, with conditional and pattern-matching.</p>
<p>What if we want to process a sequence of types? For example, we could want to compute the common type of a sequence of types:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    <span class="co">// Default version: n arguments (n &gt; 0)</span>
    <span class="kw">typename</span> CommonType(<span class="kw">typename</span> T, <span class="kw">typename</span>... Ts) {
        <span class="co">// iterate over a pack of types</span>
        <span class="co">// `for...` is implied because we are in a type function and operating on a</span>
        <span class="co">// parameter pack.</span>
        <span class="co">// This follows the same logic as `if` in type functions being an `if constexpr`.</span>
        <span class="kw">for</span> (<span class="kw">typename</span> U: Ts)
            T = CommonType(T, U);
        <span class="kw">return</span> T;
    }

    <span class="co">// Specialization: 1 argument</span>
    <span class="kw">typename</span> CommonType(<span class="kw">typename</span> T) {
        <span class="kw">return</span> T;
    }

    <span class="co">// Specialization: 2 arguments</span>
    <span class="kw">typename</span> CommonType(<span class="kw">typename</span> T, <span class="kw">typename</span> U) {
        ...
    }</code></pre>
<p>This implies the possibility to iterate over a pack of types. Also, types are passed &quot;by value&quot; and manipulated as values. Above, <code>T</code> is only modified in the type function, not on call site.</p>
<p>An application example of the above code is:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    <span class="kw">template</span>&lt;<span class="kw">typename</span>... Args&gt;
    CommonType(Args...) compute(std::tuple&lt;Args...&gt; <span class="dt">const</span>&amp; t);</code></pre>
<p>In a similar way, we could write a type function returning the type with the biggest size. This shows the use of an integral value:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    <span class="kw">typename</span> BiggestType(<span class="kw">typename</span> T, <span class="kw">typename</span>... Ts) {
        std::size_t N = <span class="kw">sizeof</span>(T);
        <span class="kw">for</span> (<span class="kw">typename</span> U: Ts) {
            <span class="kw">if</span> (<span class="kw">sizeof</span>(U) &gt; N) {
                T = U;
                N = <span class="kw">sizeof</span>(T);
            }
        }
        <span class="kw">return</span> T;
    }

    <span class="co">// In another context, we can now write:</span>
    <span class="kw">typename</span> T = BiggestType(Args...);</code></pre>
<p>Both <code>CommonType</code> and <code>BiggestType</code> are examples of reductions. We will see more on this in <a href="#e.-sum-types-and-product-types">operator overloading section</a>.</p>
<h2 id="adl"><a href="#adl">8. ADL</a></h2>
<p>We propose that type functions follow ADL, as shows the following example.</p>
<p>Sometimes, we don't want to provide <code>operator&lt;</code> for a type because there is no natural total ordering. But we still want our type to be usable as a key of an associative container (<code>std::map</code>, <code>std::set</code>...). In this case, we want to specialize <code>std::less</code>.</p>
<p>Consider:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    <span class="co">// Defined in a third-party library.</span>
    <span class="kw">namespace</span> game {
        <span class="kw">class</span> player {
            string name;
            <span class="dt">int</span> score;
        <span class="kw">public</span>:
            <span class="co">// No natural total ordering: should we first order on name and then on</span>
            <span class="co">// score, or the opposite? Let's not provide `operator&lt;` and let the</span>
            <span class="co">// user decide. But we still want this type to be easily usable</span>
            <span class="co">// as an associative container key.</span>
        };
    } <span class="co">// So we have to close our namespace...</span>

    <span class="co">// Reopen std...</span>
    <span class="kw">namespace</span> std {
        <span class="co">// ...and add our `less` specialization</span>
        <span class="kw">template</span>&lt;&gt;
        <span class="kw">struct</span> less&lt;game::player&gt; {
            <span class="kw">constexpr</span> <span class="dt">bool</span> <span class="kw">operator</span>()(game::player <span class="dt">const</span>&amp; a, game::player <span class="dt">const</span>&amp; b) <span class="dt">const</span> {
                <span class="kw">return</span> a.name &lt; b.name || (!(b.name &lt; a.name) &amp;&amp; a.score &lt; b.score);
                <span class="co">// Note: We could also order first on the score to be more efficient.</span>
            }
        };
    }

    <span class="co">// Now we close `std` and reopen `game` to continue our work.</span>
    <span class="kw">namespace</span> game {
        <span class="co">// ...</span>
    }</code></pre>
<p>Having to reopen namespace <code>std</code> to put our code inside it is ugly and verbose.</p>
<p>Consider now the type function alternative with ADL:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    <span class="kw">namespace</span> std {
        <span class="co">// Slight modification of `set`: it now uses the type function `Less`</span>
        <span class="co">// to get the `Compare` type.</span>
        <span class="co">// Note: for the sake of simplicity, this example ignores the allocator type.</span>
        <span class="kw">template</span>&lt;<span class="kw">typename</span> Key, <span class="kw">typename</span> Compare = Less(Key)&gt;
        <span class="kw">class</span> set;

        <span class="co">// General definition:</span>
        <span class="co">// `Less` takes a totally ordered type and return a binary predicate type.</span>
        BinaryPredicate Less(TotallyOrdered T) {
            <span class="co">// We return an anonymous type.</span>
            <span class="kw">return</span> <span class="kw">struct</span> {
                <span class="kw">constexpr</span> <span class="dt">bool</span> <span class="kw">operator</span>()(T <span class="dt">const</span>&amp; a, T <span class="dt">const</span>&amp; b) <span class="dt">const</span> {
                    <span class="kw">return</span> a &lt; b;
                }
            };
        }
    }

    <span class="co">// In our code:</span>
    <span class="kw">namespace</span> game {
        <span class="kw">class</span> player {
            <span class="co">// ...</span>
        };

        <span class="co">// We specialize `Less` for the type `player`.</span>
        <span class="co">// See explanations below on the `requires` clause and the use of `==`.</span>
        BinaryPredicate Less(<span class="kw">typename</span> T) requires(T == player) {
            <span class="kw">return</span> <span class="kw">struct</span> {
                <span class="kw">constexpr</span> <span class="dt">bool</span> <span class="kw">operator</span>()(T <span class="dt">const</span>&amp; a, T <span class="dt">const</span>&amp; b) <span class="dt">const</span> {
                    <span class="kw">return</span> a.name &lt; b.name || (!(b.name &lt; a.name) &amp;&amp; a.score &lt; b.score);
                }
            };
        }
    }

    <span class="co">// In yet another namespace:</span>
    <span class="kw">namespace</span> xyz {
        <span class="dt">void</span> my_function() {
            <span class="co">// Will use the `Less` version from namespace `game` as expected.</span>
            std::set&lt;game::player&gt; players;
        }
    }</code></pre>
<p>With type functions we don't have to reopen namespace <code>std</code> anymore and the mechanism to find the right overload (ADL) is well-known. This results in shorter and clearer code. The previous example is built around <code>std::less</code>, but another good example would be with <code>std::hash</code>.</p>
<p>The <code>Less</code> specialization for type <code>player</code> uses a <code>requires</code> clause to restrict this overload the <code>player</code> type only. This relies on <code>==</code> which is defined on types with the expected semantics (its external behavior is identical to <code>std::is_same_v</code>). This shows that having operators defined on types is desirable. See <a href="#operator-overloading">section 10</a> for more examples.</p>
<p>In a previous example (see <a href="#overloading-continued">section 4</a>), we did not use a <code>requires</code> clause with <code>==</code> to restrict a type function specialization to one type, but we used instead the <code>concept()</code> builtin function. These two solutions are here equivalent:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    <span class="co">// `requires` + `==` solution:</span>
    BinaryPredicate Less(<span class="kw">typename</span> T) requires(T == player) {
        <span class="kw">return</span> <span class="kw">struct</span> {
            <span class="kw">constexpr</span> <span class="dt">bool</span> <span class="kw">operator</span>()(T <span class="dt">const</span>&amp; a, T <span class="dt">const</span>&amp; b) <span class="dt">const</span> {
                <span class="kw">return</span> a.name &lt; b.name || (!(b.name &lt; a.name) &amp;&amp; a.score &lt; b.score);
            }
        };
    }

    <span class="co">// equivalent to `concept()` solution:</span>
    BinaryPredicate Less(concept(player) T) {
        <span class="kw">return</span> <span class="kw">struct</span> {
            <span class="kw">constexpr</span> <span class="dt">bool</span> <span class="kw">operator</span>()(T <span class="dt">const</span>&amp; a, T <span class="dt">const</span>&amp; b) <span class="dt">const</span> {
                <span class="kw">return</span> a.name &lt; b.name || (!(b.name &lt; a.name) &amp;&amp; a.score &lt; b.score);
            }
        };
    }</code></pre>
<h2 id="composition"><a href="#composition">9. Composition</a></h2>
<p>We've seen in <a href="#pattern-matching-with-switch-case">section 6</a> an example of chaining type functions:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    RemoveCv(RemoveReference(T))</code></pre>
<p>We can write a type function to compose <code>RemoveCv</code> and <code>RemoveReference</code>:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp"><span class="kw">typename</span> RemoveCvReference(<span class="kw">typename</span> T) {
    <span class="kw">return</span> RemoveCv(RemoveReference(T));
}</code></pre>
<p>Also, assuming <code>RemoveCv</code> and <code>RemoveReference</code> also remove <code>cv</code>-qualifiers and reference qualifiers from member functions (not in the standard), we can simplify <code>CodomainType</code> by reducing the pattern-matching to these cases:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    <span class="kw">typename</span> CodomainType(FunctionObject F) { <span class="co">// `FunctionObject` is a concept</span>
        ...
        <span class="kw">switch</span> (RemoveCvReference(F)) {
        <span class="kw">case</span> Ret (...):                      <span class="co">// function</span>
        <span class="kw">case</span> Ret (*)(...):                   <span class="co">// pointer to function</span>
        <span class="kw">case</span> Ret (C::*)(...):                <span class="co">// pointer to member function</span>
                                             <span class="co">// (noexcept variants omitted)</span>
            <span class="kw">return</span> RemoveCvReference(Ret);
        <span class="kw">default</span>:                             <span class="co">// user-defined type</span>
            ...
        }
    }</code></pre>
<p>Since we compose types with (type) functions, we can define a composition type function. For that, we define a <code>TypeFunction</code> concept:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    <span class="co">// A type function takes a type and returns a type.</span>
    <span class="kw">template</span>&lt;<span class="kw">typename</span> F&gt;
    concept TypeFunction = requires(<span class="kw">typename</span>... Ts) { <span class="co">// new syntax (see below).</span>
        { F(Ts...) } -&gt; <span class="kw">typename</span>;
    };</code></pre>
<p>This implies an adaptation of C++20 concepts to introduce types in <code>requires</code> clause. The exact impact of this change is to be determined.</p>
<p>Every type function we defined so far models of course the <code>TypeFunction</code> concept.</p>
<p>We also propose that lambda syntax is extended to operate on types: when operating on types, the constructed closure is a type function.</p>
<p>With this, we can write:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    <span class="co">// The domain of `G` must match the codomain of `F`.</span>
    TypeFunction Compose(TypeFunction G, TypeFunction F) {
        <span class="co">// A lambda operating on types is a type function.</span>
        <span class="co">// Notice the parallel with runtime programming.</span>
        <span class="kw">return</span> [=](<span class="kw">typename</span>... Ts) { <span class="co">// the only allowed capture mode is by value.</span>
            <span class="kw">return</span> G(F(Ts...));
        };
    }</code></pre>
<p>We can now rewrite <code>RemoveCvReference</code> in this way:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    <span class="kw">typename</span> RemoveCvReference = Compose(RemoveCv, RemoveReference);</code></pre>
<p>And possibly use it in other compositions:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    <span class="co">// `CodomainOfValueType` algorithm:</span>
    <span class="co">// - first removes cv and reference qualifiers</span>
    <span class="co">// - then takes the value type</span>
    <span class="co">// - then takes the codomain type</span>
    <span class="co">// This makes sense for example if the input type is a</span>
    <span class="co">// (possibly reference to cv-qualified) container of functions.</span>
    <span class="kw">typename</span> CodomainOfValueType = Compose(Compose(CodomainType, ValueType), RemoveCvReference);</code></pre>
<p>See <a href="#d.-composition-operator">section 10. d</a> for an alternative syntax. The ability to perform simple compositions opens the door to more complex composition, as explained in <a href="#optional-and-composition">section III. 1</a>.</p>
<h2 id="operator-overloading"><a href="#operator-overloading">10. Operator overloading</a></h2>
<h3 id="a.-comparison-operators"><a href="#a.-comparison-operators">a. Comparison operators</a></h3>
<p>We propose that <code>==</code> and <code>!=</code> are defined on types with the expected semantics (<code>A == B</code> gives the same result as <code>std::is_same_v&lt;A, B&gt;</code>). These operators allow to express much more clearly the intention of the user.</p>
<p>Compare:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    <span class="co">// constructor of `my_type`</span>
    <span class="co">// We prevent it to &quot;swallow&quot; the copy constructor</span>
    <span class="co">// (simplification: doesn't handle derived types).</span>
    <span class="kw">template</span>&lt;<span class="kw">typename</span> T,
      <span class="kw">typename</span> = std::enable_if_t&lt;std::negation_v&lt;std::is_same&lt;std::decay_t&lt;T&gt;, my_type&gt;&gt;&gt;&gt;
    my_type(T&amp;&amp; t);</code></pre>
<p>with</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    <span class="kw">template</span>&lt;<span class="kw">typename</span> T, <span class="kw">typename</span> = std::enable_if_t&lt;std::decay_t&lt;T&gt; != my_type&gt;&gt;
    my_type(T&amp;&amp; t);</code></pre>
<p>or if we assume standard type function equivalents:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    <span class="kw">template</span>&lt;<span class="kw">typename</span> T, <span class="kw">typename</span> = std::EnableIf(std::Decay(T) != my_type)&gt;
    my_type(T&amp;&amp; t);</code></pre>
<p>Another use of <code>==</code> has already been seen in <a href="#adl">section 8</a> to restrict a type function to a single type.</p>
<p>It is also useful with respect to <code>void</code>: as long as <code>void</code> is an exceptional type in the type system, handling it requires special cases (e.g. <code>std::future&lt;void&gt;</code>, composing <code>void (T)</code> with other functions, etc.):</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    <span class="kw">typename</span> MyTypeFunction(<span class="kw">typename</span> T) {
        <span class="kw">if</span> (T == <span class="dt">void</span>) { <span class="co">// special case</span>
            ...
        } <span class="kw">else</span> {
            ...
        }
    }</code></pre>
<h3 id="b.-relational-operators"><a href="#b.-relational-operators">b. Relational operators</a></h3>
<p>It is also possible to define a total ordering on types by using their type index (assuming type index comparisons are <code>constexpr</code>).</p>
<p>First, we define a type attribute that associates a type to its index (more on type attributes in <a href="#a.-type-attributes">section 12. a</a>):</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">  std::type_index indexof(<span class="kw">typename</span> T) {
      <span class="kw">return</span> std::type_index(<span class="kw">typeid</span>(T));
  }</code></pre>
<p>Then we can define relational operators:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    <span class="dt">bool</span> <span class="kw">operator</span>&lt;(<span class="kw">typename</span> A, <span class="kw">typename</span> B) {
        <span class="kw">return</span> indexof(A) &lt; indexof(B);
    }

    <span class="dt">bool</span> <span class="kw">operator</span>&gt;(<span class="kw">typename</span> A, <span class="kw">typename</span> B) {
        <span class="kw">return</span> B &lt; A;
    }

    <span class="dt">bool</span> <span class="kw">operator</span>&lt;=(<span class="kw">typename</span> A, <span class="kw">typename</span> B) {
        <span class="kw">return</span> !(B &lt; A)
    }

    <span class="dt">bool</span> <span class="kw">operator</span>&gt;=(<span class="kw">typename</span> A, <span class="kw">typename</span> B) {
        <span class="kw">return</span> !(A &lt; B)
    }</code></pre>
<p>This definition of <code>&lt;</code> is indeed a total ordering: it is associative and it respects the trichotomy law (only one of the following holds: <code>A &lt; B</code>, <code>B &lt; A</code>, or <code>A == B</code>).</p>
<p>It is also possible to define weak orderings (meaning, in the trichotomy law equality is replaced by an equivalence) on types by using <code>sizeof(T)</code> or <code>alignof(T)</code>.</p>
<p>A use example of <code>&lt;</code> is given in the <a href="#e.-sum-types-and-product-types">section on sum and product types</a>.</p>
<h3 id="c.-logical-operators"><a href="#c.-logical-operators">c. Logical operators</a></h3>
<p>We can also overload operators by concept. For example, it makes sense to define <code>!</code> on predicate types as returning the complement type. In the following example, we want to keep all characteristics of the input predicate type, only negating the function call. For that, we use reflection and code injection (see <a href="#p0707">[P0707]</a>):</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    Predicate ComplementType(Predicate P) requires Class(P) {
        <span class="co">// We inject code in P (variant of p0707 syntax)</span>
        <span class="co">// Note that types are passed &quot;by value&quot;, so we are not</span>
        <span class="co">// modifying the original predicate.</span>
        <span class="co">// The algorithm is:</span>
        <span class="co">//      for each operator()</span>
        <span class="co">//          change its signature by adding a dummy int parameter</span>
        <span class="co">//          make it private</span>
        <span class="co">//          add an operator() with the original signature (i.e. without int)</span>
        <span class="co">//          make it return the complement of the original operator()</span>
        <span class="kw">return</span> -&gt;(P) {<span class="kw">constexpr</span> {
            <span class="kw">for</span> (<span class="dt">auto</span> f: $P.functions()) {
                <span class="kw">if</span> (f.name == <span class="st">&quot;operator()&quot;</span>) {
                    <span class="co">// Change the signature of the original `operator()` to</span>
                    <span class="co">// leave room for the new one.</span>
                    f.parameters().push_back($int);
                    f.make_private();

                    <span class="co">// Inject a new `operator()` negating the original one.</span>
                    -&gt; {
                        <span class="dt">bool</span> <span class="kw">operator</span>()(f.parameters()$) f.qualifiers()$ {
                            <span class="co">// Call the original version.</span>
                            <span class="kw">constexpr</span> {
                                f.parameters().pop_back();
                                -&gt; { <span class="kw">return</span> ! <span class="kw">operator</span>()(f.parameter_names()$, <span class="dv">0</span>); }
                            }
                        }
                    }
                }
            }
        }};
    }

    <span class="co">// Simply forward to `ComplementType`</span>
    Predicate <span class="kw">operator</span>!(Predicate P) requires Class(P) {
        <span class="kw">return</span> ComplementType(P);
    }</code></pre>
<p>Now we can negate a predicate type. For example:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    <span class="kw">typename</span> greater_eq = !Less(<span class="dt">int</span>);</code></pre>
<p>Also, in the definition of <code>ComplementType</code>, <code>$P.functions()</code> is really a type attribute (see <a href="#a.-type-attributes">section 12. a</a>) and could be written more consistently <code>functions(P)</code>:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    <span class="kw">for</span> (<span class="dt">auto</span> f: functions(P)) {
        <span class="kw">if</span> (f.name == <span class="st">&quot;operator()&quot;</span>) {
            ... <span class="co">// idem</span>
        }
    }</code></pre>
<p>Finally, the type manipulated by <code>operator!</code> must be a <code>Predicate</code> type and a <code>Class</code> type. We'll see in <a href="#optional-and-composition">section III 1.</a> a more powerful way to compose concepts.</p>
<p>We can also define other boolean operators, such as <code>&amp;&amp;</code>:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    Predicate ConjunctionType(Predicate P0, Predicate P1) {
        <span class="co">// Here, we don't inject code. We just embed the two predicates</span>
        <span class="co">// into a new predicate type:</span>
        <span class="kw">return</span>
            <span class="kw">class</span> conj {
                P0 p0;
                P1 p1;
            <span class="kw">public</span>:
                <span class="co">// A predicate type is regular:</span>
                <span class="kw">friend</span> <span class="dt">bool</span> <span class="kw">operator</span>==(conj <span class="dt">const</span>&amp; x, conj <span class="dt">const</span>&amp; y) {
                    <span class="kw">return</span> x.p0 == y.p0 &amp;&amp; x.p1 == y.p1;
                }
                <span class="co">// A predicate type doesn't modify its argument.</span>
                <span class="kw">template</span>&lt;<span class="kw">typename</span>... Args&gt;
                <span class="dt">bool</span> <span class="kw">operator</span>()(Args <span class="dt">const</span>&amp;... args) {
                    <span class="kw">return</span> p0(args...) &amp;&amp; p1(args...);
                }
                <span class="co">// `const` version</span>
                <span class="kw">template</span>&lt;<span class="kw">typename</span>... Args&gt;
                <span class="dt">bool</span> <span class="kw">operator</span>()(Args <span class="dt">const</span>&amp;... args) <span class="dt">const</span> {
                    <span class="kw">return</span> p0(args...) &amp;&amp; p1(args...);
                }
            };
    }

    <span class="co">// Simply forward to `ConjunctionType`</span>
    Predicate <span class="kw">operator</span>&amp;&amp;(Predicate P0, Predicate P1) {
        <span class="kw">return</span> ConjunctionType(P0, P1);
    }</code></pre>
<p>Note: <code>ComplementType</code> and <code>ConjunctionType</code> are indeed type constructors: they take a type and create a new type (see <a href="#b.-type-constructors">section 12. b</a>). A unary type constructor (such as <code>ComplementType</code>) is similar to a <a href="#p0707">[P0707 ]</a>'s metaclass (see <a href="#metaclasses">section 11</a>). But a n-ary type constructor (such as <code>ConjunctionType</code>) cannot <em>a priori</em> be made with a metaclass.</p>
<p>We can now use <code>&amp;&amp;</code> to create new predicates:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    <span class="co">// `is_male_t`, `has_brother_t` and `has_sister_t` are predicates.</span>
    Predicate is_only_son_t = is_male_t &amp;&amp; !has_brother_t &amp;&amp; !has_sister_t;

    <span class="co">// Compare the readability of the previous form with this one:</span>
    Predicate is_only_son_t = ConjunctionType(ConjunctionType(is_male_t,
        ComplementType(has_brother_t)), ComplementType(has_sister_t));

    <span class="co">// Or if we only had object functions (i.e. functions on objects),</span>
    <span class="co">// assuming `&amp;&amp;` and `!` had been overloaded accordingly:</span>
    Predicate is_only_son_t = Decay(<span class="kw">decltype</span>(
           std::declval&lt;is_male_t&gt;()
        &amp;&amp; !std::declval&lt;has_brother_t&gt;()
        &amp;&amp; !std::declval&lt;has_sister_t&gt;()
    ));</code></pre>
<p>Having type function operators is readable and non-ambiguous.</p>
<p>Some use of conjunction and negation are common so it is useful to define type functions such as <code>EquivalenceType</code>:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    <span class="co">// A relation is a homogeneous binary predicate</span>
    <span class="co">// (i.e. a predicate on two elements of the same type).</span>
    <span class="co">// Precondition: R is a weak ordering</span>
    Relation EquivalenceType(Relation R) {
        <span class="co">// Assume the existence of `ConverseType` that swaps</span>
        <span class="co">// the order of the two parameters of a relation type:</span>
        <span class="co">// with a relation r, the converse of r(a, b) is r(b, a).</span>
        <span class="co">// The returned relation is true for two values if none</span>
        <span class="co">// is &quot;less&quot; than the other one, which forms an equivalence.</span>
        <span class="kw">return</span> !R &amp;&amp; !ConverseType(R);
    }</code></pre>
<p>We can use it for example to transform a total ordering into an equivalence and compare sequence of elements:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    <span class="co">// We want to know if two strings are equivalent when we ignore case and accents.</span>
    <span class="co">// `is_char_before_nocase_noaccent_t` is a weak ordering.</span>
    <span class="co">// E.g. with `before` an instance of this type, the following are true:</span>
    <span class="co">// before('a', 'b'), before('b', 'c'), before('a', 'c'),</span>
    <span class="co">// !before('a', 'a'), !before('b', 'a'), !before('c', 'a'),</span>
    <span class="co">// !before('A', 'a'), !before('a', 'A'), !before('a', 'à'), !before('à', 'a'),</span>
    <span class="co">// !before('â', 'a'), !before('a', 'â'), etc.</span>

    std::string s0 = ...;
    std::string s1 = ...;

    <span class="co">// `lexicographical_equivalent` requires an equivalence.</span>
    <span class="co">// For a definition of `lexicographical_equivalent`, see</span>
    <span class="co">// `Elements of Programming`, section 7.4.</span>
    <span class="kw">if</span> (lexicographical_equivalent(begin(s0), end(s0), begin(s1), end(s1),
          EquivalenceType(is_char_before_nocase_noaccent_t){})) {
        ...
    }</code></pre>
<h3 id="d.-composition-operator"><a href="#d.-composition-operator">d. Composition operator</a></h3>
<p>In <a href="#composition">section 9</a>, we composed type function with this notation:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    <span class="kw">typename</span> CodomainOfValueType = Compose(Compose(CodomainType, ValueType), RemoveCvReference);</code></pre>
<p>which has the form:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    <span class="co">// x is a function that first applies f, then g on the result of f, then h on the result of g.</span>
    x = compose(h, compose(g, f));</code></pre>
<p>The longer the chain of composition, the less readable this notation is, and a linear notation such as the following one could be preferable:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    <span class="co">// x is a function that first applies f, then g on the result of f, then h on the result of g.</span>
    x = f | g | h;</code></pre>
<p>So we define <code>|</code> for type functions:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    TypeFunction <span class="kw">operator</span>|(TypeFunction F, TypeFunction G) {
        <span class="kw">return</span> Compose(G, F);
    }</code></pre>
<p>Now we can rewrite</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    <span class="kw">typename</span> CodomainOfValueType = Compose(Compose(CodomainType, ValueType), RemoveCvReference);</code></pre>
<p>as:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    <span class="kw">typename</span> CodomainOfValueType = RemoveCvReference | ValueType | CodomainType;

    <span class="co">// C is a container of function objects</span>
    <span class="kw">template</span>&lt;Container C&gt;
    <span class="dt">auto</span> do_stuff(C&amp;&amp; functions) {
        std::vector&lt;CodomainOfValueType(C)&gt; results;
        <span class="co">// ...</span>
    }</code></pre>
<p>or directly in-place for a one-shot use:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    <span class="co">// C is a container of function objects</span>
    std::vector&lt;(RemoveCvReference | ValueType | CodomainType)(C)&gt; results;</code></pre>
<p>We will see more complex compositions in the <a href="#optional-and-composition">section III 1</a>.</p>
<h3 id="e.-sum-types-and-product-types"><a href="#e.-sum-types-and-product-types">e. Sum types and product types</a></h3>
<p>On a more theoretical side, there exists an algebra of types that defines sum and product on types. Sum corresponds to <code>union</code> (or <code>variant</code>) and product to <code>struct</code> (or <code>tuple</code>). There is a special type that behaves as the <code>0</code> of the sum, and another one that behaves as the <code>1</code> of the multiplication. Also, the product distributes over the sum. There is also exponentiation that corresponds to function types, but this is not considered in the following examples for the sake of simplicity.</p>
<p>The natural way to express sum types and product types is to use operators <code>+</code> and <code>*</code>. As before, we first define type functions and then implement operators as simply forwarding to these type functions.</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    <span class="co">// We want to avoid nesting to make the operation associative.</span>
    <span class="co">// E.g. `OpSumType(OpSumType(int, bool), char)` is the type</span>
    <span class="co">// `variant&lt;int, bool, char&gt;` instead of `variant&lt;variant&lt;int, bool&gt;, char&gt;`.</span>
    <span class="co">// Similarly, `OpSumType(int, OpSumType(bool, char))` is the type</span>
    <span class="co">// `variant&lt;int, bool, char&gt;` instead of `variant&lt;int, variant&lt;bool, char&gt;&gt;`.</span>
    <span class="kw">typename</span> OpSumType(<span class="kw">typename</span> A, <span class="kw">typename</span> B) {
        <span class="kw">switch</span> (B) {
        <span class="kw">case</span> std::variant&lt;<span class="kw">typename</span>...{ArgsB}&gt;:
            <span class="kw">return</span> detail::OpSumType(A, ArgsB...);
        <span class="kw">default</span>:
            <span class="kw">return</span> detail::OpSumType(A, B);
        }
    }

    <span class="kw">namespace</span> detail {
        <span class="kw">typename</span> OpSumType(<span class="kw">typename</span> A, <span class="kw">typename</span>... ArgsB) {
            <span class="kw">switch</span> (A) {
            <span class="kw">case</span> std::variant&lt;<span class="kw">typename</span>...{ArgsA}&gt;:
                <span class="kw">return</span> std::variant&lt;ArgsA..., ArgsB...&gt;;
            <span class="kw">default</span>:
                <span class="kw">return</span> std::variant&lt;A, ArgsB...&gt;;
            }
        }
    }

    <span class="kw">typename</span> <span class="kw">operator</span>+(<span class="kw">typename</span> A, <span class="kw">typename</span> B) {
        <span class="kw">return</span> OpSumType(A, B);
    }

    <span class="co">// `operator*` is similar to `operator+` but is implemented with a</span>
    <span class="co">// `OpProductType` type function that returns a `std::tuple` type instead</span>
    <span class="co">// of a `std::variant` type.</span>
    <span class="co">// Thus, `OpProductType(int, bool)` is the type `tuple&lt;int, bool&gt;` and both</span>
    <span class="co">// `OpProductType(OpProductType(int, bool), char)` and</span>
    <span class="co">// `OpProductType(int, OpProductType(bool, char))` are the type `tuple&lt;int, bool, char&gt;`.</span>

    <span class="kw">typename</span> <span class="kw">operator</span>*(<span class="kw">typename</span> A, <span class="kw">typename</span> B) {
        <span class="kw">return</span> OpProductType(A, B);
    }</code></pre>
<p>Note that in the previous code, <a href="#p0095">[P0095]</a>'s <code>lvariant</code> could be used instead of <code>std::variant</code> for an alternative implementation.</p>
<p>Also, an alternative to the previous implementation of <code>OpSumType</code> and <code>OpProductType</code> using a <code>switch case</code> is to do pattern matching is to specialize functions, but it might be more cumbersome:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    <span class="kw">typename</span> OpSumType(<span class="kw">typename</span> A, <span class="kw">typename</span> B);

    <span class="kw">typename</span> OpSumType(concept(std::variant&lt;<span class="kw">typename</span>...{ArgsA}&gt;) A, <span class="kw">typename</span> B);

    <span class="kw">typename</span> OpSumType(<span class="kw">typename</span> A, concept(std::variant&lt;<span class="kw">typename</span>...{ArgsB}&gt;) B);

    <span class="kw">typename</span> OpSumType(concept(std::variant&lt;<span class="kw">typename</span>...{ArgsA}&gt;) A,
                       concept(std::variant&lt;<span class="kw">typename</span>...{ArgsB}&gt;) B);

    <span class="co">// Idem for `OpProductType` with `std::tuple` instead of `std::variant`.</span></code></pre>
<p>We can now use these operators to define algebraic datatypes:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    <span class="kw">typename</span> name_or_id_t = std::string + <span class="dt">int</span>;
    name_or_id_t n0{<span class="st">&quot;bob783&quot;</span>};
    name_or_id_t n1{<span class="dv">95248</span>};

    <span class="kw">typename</span> name_and_score_t = std::string * <span class="dt">int</span>;
    name_and_score_t n2{<span class="st">&quot;bob783&quot;</span>, <span class="dv">10000</span>};

    <span class="co">// `uninstanciable_t` is roughly the `0` of the sum.</span>
    <span class="co">// Because it cannot be instanciated, it does not add real information</span>
    <span class="co">// to the type.</span>
    <span class="kw">struct</span> uninstanciable_t {
        uninstanciable_t() = <span class="kw">delete</span>;
    };

    <span class="kw">typename</span> name_t = std::string + uninstanciable_t;
    name_t n3{<span class="st">&quot;bob&quot;</span>};

    <span class="co">// std::monostate is roughly the `1` of the product because it does not</span>
    <span class="co">// add any real information to the type.</span>
    <span class="kw">typename</span> name_t = std::string * std::monostate;
    name_t n4{<span class="st">&quot;bob&quot;</span>};

    <span class="co">// Here is an example of distributivity of the product over the sum.</span>
    <span class="co">// A &quot;registered player&quot; has a status. He also has either name or an id:</span>
    <span class="kw">typename</span> registered_player_0_t = status_t * (std::string + <span class="dt">int</span>);

    <span class="co">// Equivalent to:</span>
    <span class="kw">typename</span> registered_player_1_t = (status_t * std::string) + (status_t * <span class="dt">int</span>);

    <span class="co">// Note that `registered_player_0_t` is not the same type as `registered_player_1_t`.</span>
    <span class="co">// But they are equivalent (isomorphic) in the sense that it is possible to convert</span>
    <span class="co">// from one to the other and convert back without &quot;losing&quot; any information.</span></code></pre>
<p>We can have arbitrary long chains of <code>+</code> or <code>*</code>, and performing a sum or a product is a special case of reduction:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    <span class="kw">typename</span> ReduceType(TypeFunction Op, <span class="kw">typename</span> T, <span class="kw">typename</span>... Ts) {
        <span class="kw">for</span> (<span class="kw">typename</span> U: Ts)
            T = Op(T, U);
        <span class="kw">return</span> T;
    }

    <span class="kw">typename</span> SumType(<span class="kw">typename</span> T, <span class="kw">typename</span>... Ts) {
        <span class="co">// Reduce in terms of the binary version:</span>
        <span class="kw">return</span> ReduceType(OpSumType, T, Ts...);
    }

    <span class="kw">typename</span> ProductType(<span class="kw">typename</span> T, <span class="kw">typename</span>... Ts) {
        <span class="co">// Reduce in terms of the binary version:</span>
        <span class="kw">return</span> ReduceType(OpProductType, T, Ts...);
    }</code></pre>
<p>In section about <a href="#processing-sequence-of-types-with-for"><code>for</code> applied to sequence of types</a>, we gave as an example the type functions <code>BiggestType</code> and <code>CommonType</code>. They are also special cases of reduction and can be reimplemented this way:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    <span class="kw">typename</span> CommonType(<span class="kw">typename</span> T, <span class="kw">typename</span>... Ts) {
        TypeFunction Op = [](<span class="kw">typename</span> A, <span class="kw">typename</span> B) {
            ...
        };
        <span class="kw">return</span> ReduceType(Op, T, Ts...);
    }

    <span class="kw">typename</span> BiggestType(<span class="kw">typename</span> T, <span class="kw">typename</span>... Ts) {
        TypeFunction Op = [](<span class="kw">typename</span> A, <span class="kw">typename</span> B) {
            <span class="kw">if</span> (<span class="kw">sizeof</span>(B) &gt; <span class="kw">sizeof</span>(A)) <span class="kw">return</span> B;
            <span class="kw">else</span> <span class="kw">return</span> A;
        };
        <span class="kw">return</span> ReduceType(Op, T, Ts...);
    }</code></pre>
<h2 id="metaclasses"><a href="#metaclasses">11. Metaclasses</a></h2>
<h3 id="a.-metaclasses-as-type-functions"><a href="#a.-metaclasses-as-type-functions">a. Metaclasses as type functions</a></h3>
<p>A metaclass (as described in <a href="#p0707">[P0707]</a>) is primarily a mechanism to generate new types. Type functions are rather a mechanism to associate types. But coupled with other mechanisms such as code injection, type functions can also generate new types in much the same way as metaclasses.</p>
<p>Also from a logical point of view, a metaclass can be viewed as a function associating an input type (the &quot;prototype class&quot;) to a new type (the generated type).</p>
<p>For example, the metaclass <code>interface</code> used in</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    interface Shape {
        <span class="dt">int</span> area() <span class="dt">const</span>;
        <span class="dt">void</span> scale_by(<span class="dt">double</span> factor);
    };</code></pre>
<p>is expected to approximatively generate this code:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    <span class="co">// In an unspecified and unique namespace:</span>
    <span class="kw">namespace</span> __xyz {
        <span class="kw">struct</span> prototype_Shape {
            <span class="dt">int</span> area() <span class="dt">const</span>;
            <span class="dt">void</span> scale_by(<span class="dt">double</span> factor);
        };
    }
    <span class="co">/* apply `interface` on `__xyz::prototype_Shape` */</span>;</code></pre>
<p>This is equivalent to the following code with <code>interface</code> being now an equivalent type function:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    <span class="kw">typename</span> Shape = interface(
        <span class="kw">struct</span> { <span class="co">// no need to name the struct</span>
            <span class="dt">int</span> area() <span class="dt">const</span>;
            <span class="dt">void</span> scale_by(<span class="dt">double</span> factor);
        }
    );</code></pre>
<p>In <a href="#p0707">[P0707]</a>, composing metaclass is done in an imperative way:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    <span class="co">// `value` and `serializable` are metaclasses.</span>
    <span class="kw">constexpr</span> <span class="dt">void</span> serializable_value(meta::type target, <span class="dt">const</span> meta::type source) {
      value(target, source);
      serializable(target, source);
    };</code></pre>
<p>With type functions, composition is simply function composition:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    <span class="co">// `value` and `serializable` are now type functions equivalent</span>
    <span class="co">// to the previous metaclasses.</span>
    <span class="kw">typename</span> point = serializable(value(
        <span class="kw">struct</span> {
            <span class="dt">int</span> x;
            <span class="dt">int</span> y;
        }
    ));</code></pre>
<p>Also, note that a metaclass takes an &quot;in/out&quot; argument (the target) and return <code>void</code>. This makes a metaclass different from a mathematical function, preventing the usual function composition and more advanced compositions (see <a href="#optional-and-composition">section III 1</a>).</p>
<p>If we want to give a name to our previous composition, we can write:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    <span class="kw">typename</span> serializable_value = value | serializable;

    <span class="kw">typename</span> point = serializable_value(
        <span class="kw">struct</span> {
            <span class="dt">int</span> x;
            <span class="dt">int</span> y;
        }
    );</code></pre>
<p>Thus, we have a unified way to perform composition.</p>
<p>We can also ensure at different levels that the returned type models some concept:</p>
<ul>
<li>in the definition of a type function, e.g.:</li>
</ul>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    Regular value(<span class="kw">typename</span> T); <span class="co">// the type returned by `value` models the `Regular` concept</span></code></pre>
<ul>
<li>on call site:</li>
</ul>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    Regular point = serializable_value(
        <span class="kw">struct</span> {
            <span class="dt">int</span> x;
            <span class="dt">int</span> y;
        }
    );</code></pre>
<p>As a side note, the notation</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    serializable_value point {
        <span class="dt">int</span> x;
        <span class="dt">int</span> y;
    };</code></pre>
<p>could be introduced as syntactic sugar for</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    <span class="kw">typename</span> point = serializable_value(
        <span class="kw">struct</span> {
            <span class="dt">int</span> x;
            <span class="dt">int</span> y;
        }
    );</code></pre>
<p>Thus, it seems metaclasses are only a specific case of type functions (with potential extra syntactic sugar).</p>
<p>Now if we use the same code injection mechanism as in <a href="#p0707">[P0707]</a>, we can write for example:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    <span class="co">// `value` is a type function that adds a memberwise `operator==` if it doesn't</span>
    <span class="co">// already exist (this is a simplified version for the sake of example).</span>
    <span class="kw">typename</span> value(<span class="kw">typename</span> T) {
        <span class="co">// Inject code in T, creating a new type (the input type is not modified):</span>
        <span class="kw">return</span> -&gt;(T) {
            <span class="kw">constexpr</span> {
                <span class="co">// If there is no `operator==` defined:</span>
                <span class="kw">if</span> (! requires(T a) { a == a; }) -&gt; {
                    <span class="kw">friend</span> <span class="dt">bool</span> <span class="kw">operator</span>==(T <span class="dt">const</span>&amp; a, T <span class="dt">const</span>&amp; b) {
                        <span class="kw">constexpr</span> {
                            <span class="kw">for</span> (<span class="dt">auto</span> v: variables(T)) <span class="co">// or $T.variables()</span>
                                -&gt; { <span class="kw">if</span> (! (a.(v.name)$ == b.(v.name)$)) <span class="kw">return</span> <span class="kw">false</span>; }
                        }
                        <span class="kw">return</span> <span class="kw">true</span>;
                    }
                }
            }
            <span class="co">// ...</span>
        };
    }</code></pre>
<p>Since types are passed &quot;by value&quot; to type functions, the code is injected in a copy of <code>T</code> and the original <code>T</code> is not modified. Injecting in the copy of an existing type is interesting if we only want to add methods and members, or if we want to add checks.</p>
<p>If we prefer to start from scratch by injecting in an empty type, we can write:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    <span class="kw">typename</span> value(<span class="kw">typename</span> T) {
        <span class="kw">typename</span> empty = <span class="kw">struct</span> {};
        <span class="kw">return</span> -&gt;(empty) {
            <span class="co">// fill `empty`</span>

            <span class="co">// Because `struct` was used, everything is public by default.</span>

            <span class="co">// We could also have written `typename empty = class {};`</span>
            <span class="co">// to have everything private by default.</span>
        };
    }</code></pre>
<p>Or if we don't need to name the type:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    <span class="kw">typename</span> value(<span class="kw">typename</span> T) {
        <span class="kw">return</span> -&gt;(<span class="kw">struct</span> {}) { <span class="co">// or `-&gt;(class {})`</span>
            <span class="co">// ...</span>
        };
    }</code></pre>
<p>In fact, any expression yielding a type is admissible:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    <span class="co">// A value is a special kind of basic_value.</span>
    <span class="kw">typename</span> value(<span class="kw">typename</span> T) {
        <span class="kw">return</span> -&gt;(basic_value(<span class="kw">struct</span> {})) {
            <span class="co">// ...</span>
        };
    }</code></pre>
<p>or leveraging operators:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    <span class="kw">typename</span> my_variant_value(<span class="kw">typename</span> T, <span class="kw">typename</span> U) {
        <span class="kw">if</span> (T == <span class="dt">void</span> || U == <span class="dt">void</span>) {
            ...
        } <span class="kw">else</span> {
            <span class="kw">return</span> -&gt;(value(T) + value(U)) {
                ...
            };
        }
    }</code></pre>
<p>Finally, it is also possible to fill the returned type in a more imperative manner:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    <span class="kw">typename</span> value(<span class="kw">typename</span> T) {
        <span class="kw">typename</span> Res = <span class="kw">struct</span> {};
        <span class="kw">for</span> (<span class="dt">auto</span> m: members_and_bases(T)) 
            -&gt;(Res) m;  
        <span class="co">// ...</span>
        <span class="kw">return</span> Res;
    }</code></pre>
<h3 id="b.-.is"><a href="#b.-.is">b. <code>.is</code></a></h3>
<p>In <a href="#p0707">[P0707]</a>, <code>$T.is(M)</code> is used to determine if the type <code>T</code> satisfies the requirements of the metaclass <code>M</code>. It is a predicate and has roughly the same role as the present proposal's writing <code>C(T)</code> where <code>C</code> is a concept and <code>T</code> a type. A metaclass can also be used instead of a concept in a template parameter introduction.</p>
<p>Having metaclasses acting as concepts ends up having in the language two mechanisms with overlapping responsibilities. We think this is not sound and would rather keep concepts only and add a mechanism to generate a concept from a type function. The algorithm for this would be the same as for metaclasses. With a type <code>T</code> and a type function <code>F</code>, a concept generated from <code>F</code> would evaluate to true if and only if:</p>
<ol style="list-style-type: decimal">
<li>applying <code>F</code> to <code>T</code> succeeds; and</li>
<li>the resulting type has no new members not already present in <code>T</code>.</li>
</ol>
<p>Syntactically, we can reuse the <code>concept</code> built-in function. Previously, we used it to generate a concept modeled by a unique type. Now we use it to generate a concept from a type function:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    <span class="kw">template</span>&lt;concept(value) T&gt; <span class="co">// `T` &quot;is&quot; a `value`</span>
    T my_function(T t) {
        ...
    }</code></pre>
<p>Therefore, the features of <code>.is</code> can also be brought by type functions with the benefit of having roles soundly kept separated, with non-overlapping mechanisms (types, type functions, concepts) and non-ambiguous code.</p>
<h3 id="c.-.as"><a href="#c.-.as">c. <code>.as</code></a></h3>
<p>In <a href="#p0707">[P0707]</a>, <code>$T.as(M)</code> is used to apply the metaclass <code>M</code> on the type <code>T</code>. This is what simply corresponds in the present proposal to a type function application. For example:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    <span class="co">// P0707: transforming the type `legacy_point` with the `ordered` metaclass</span>
    <span class="kw">using</span> ordered_point = $legacy_point.as(ordered);</code></pre>
<p>corresponds in terms of type functions to:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    <span class="co">// The present proposal</span>
    <span class="kw">typename</span> ordered_point = ordered(legacy_point);</code></pre>
<p>We don't need a special syntax. The writing is intuitive as it is simply function application.</p>
<p>The trick of <code>.as</code> used for 'strong typedef' can also be done with type functions:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    <span class="co">// P0707: using an empty metaclass for 'strong typedef'</span>
    <span class="kw">constexpr</span> <span class="dt">void</span> new_type(meta::type target, <span class="dt">const</span> meta::type) {}; <span class="co">// no-op metaclass fn</span>
    <span class="kw">using</span> my_T = $T.as(new_type); <span class="co">// my_T is a 'strong typedef' of T</span>
    <span class="kw">using</span> handle = $int.as(new_type);
    <span class="kw">using</span> score = $unsigned.as(new_type);
    <span class="kw">using</span> player = $string.as(new_type);</code></pre>
<p>corresponds in terms of type functions to:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    <span class="kw">typename</span> new_type(<span class="kw">typename</span> T) {
        <span class="co">// We inject no code into T, resulting in the creation of a new type</span>
        <span class="co">// similar to the original one. The logic is the same as the empty</span>
        <span class="co">// metaclass function trick.</span>
        <span class="kw">return</span> -&gt;(T) {};
    }

    <span class="kw">typename</span> my_T = new_type(T);
    <span class="kw">typename</span> handle = new_type(<span class="dt">int</span>);
    <span class="kw">typename</span> score = new_type(<span class="dt">unsigned</span>);
    <span class="kw">typename</span> player = new_type(string);</code></pre>
<p>So it seems type functions, when coupled to an injection mechanism, are a superset of metaclasses. By manipulating types directly we believe the resulting code is clearer and more consistent with the rest of the language.</p>
<h2 id="type-attributes-and-type-constructors"><a href="#type-attributes-and-type-constructors">12. Type attributes and type constructors</a></h2>
<h3 id="a.-type-attributes"><a href="#a.-type-attributes">a. Type attributes</a></h3>
<p>In <a href="#general-considerations">section I. 3</a>, we classified type functions in three categories: type functions, type attributes and type constructors. Up to this point, we have almost only talked about type functions.</p>
<p>A type attribute associates a type to a compile-time value. For example for a type <code>T</code>, <code>sizeof(T)</code> and <code>alignof(T)</code> are built-in type attributes: they both return an unsigned integral value that describes a characteristic of the type. Notice that <code>sizeof(T)</code> and <code>alignof(T)</code> already use a function syntax.</p>
<p>Other generally useful type attributes could be:</p>
<ul>
<li><code>nameof(T)</code>: returns a string naming the type</li>
<li><code>membersof(T)</code>: returns the members of a type</li>
<li><code>arityof(F)</code>: returns the number of arguments of a function object type</li>
<li>etc.</li>
</ul>
<p>The definition of a type attribute is the same as a type function, except it returns a value instead of a type:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    <span class="co">// Binary operation that blends two colors.</span>
    <span class="kw">class</span> BlendColors {
        ...
        Color <span class="kw">operator</span>()(Color <span class="dt">const</span>&amp; a, Color <span class="dt">const</span>&amp; b) <span class="dt">const</span>;
        ...
    };

    <span class="co">// `arityof` should be a built-in type attribute.</span>
    <span class="co">// This is simply an example to show the definition of a type attribute.</span>
    std::size_t arityof(concept(BlendColors) F) {
        <span class="kw">return</span> 2u;
    }</code></pre>
<h3 id="b.-type-constructors"><a href="#b.-type-constructors">b. Type constructors</a></h3>
<p>Type functions associate a type to an affiliated type. For example <code>IteratorType(T)</code> associates <code>T</code> to its iterator type. In contrast, a type constructor creates a new type. For example, the built-in &quot;pointer-to&quot; type constructor is used by appending a <code>*</code> to a type (e.g., <code>T*</code> for <code>T</code>), thus creating a new type.</p>
<ul>
<li><code>*</code>, <code>&amp;</code>, <code>const</code> can be viewed as unary type constructors (e.g., <code>int*</code>, <code>int&amp;</code>, <code>int const</code>)</li>
<li><code>[]</code> can be viewed as a binary type constructor (e.g. <code>int [5]</code>).</li>
<li><code>()</code> can be viewed as a n-ary type constructor (e.g. <code>bool (int, char)</code>)</li>
<li><code>struct</code> and <code>class</code> can be viewed as n-ary type constructors (e.g. <code>struct {int i; bool b;}</code>)</li>
</ul>
<p>Operators we defined in <a href="#c.-logical-operators">section 10. c</a> were also type constructors:</p>
<ul>
<li><code>!</code> (unary, see <code>ComplementType</code>)</li>
<li><code>&amp;&amp;</code> (binary, see <code>ConjunctionType</code>)</li>
<li>etc.</li>
</ul>
<p>Every class template is a type constructor:</p>
<ul>
<li><code>std::vector</code> (binary, e.g. <code>std::vector&lt;int&gt;</code>, <code>std::vector&lt;float, MyAlloc&gt;</code>)</li>
<li><code>std::function</code> (n-ary, e.g. <code>std::function&lt;bool (int, char)&gt;</code>)</li>
<li><code>std::tuple</code> (n-ary, e.g. <code>std::tuple&lt;int, double, float&gt;</code>)</li>
<li><code>std::variant</code> (n-ary, e.g. <code>std::variant&lt;int, double, float&gt;</code>)</li>
<li>etc.</li>
</ul>
<p>This can be formulated as type functions:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    <span class="kw">typename</span> Ptr(<span class="kw">typename</span> T) {
        <span class="kw">return</span> T*;
    }

    <span class="kw">typename</span> Vector(<span class="kw">typename</span> T, <span class="kw">typename</span> A = std::allocator&lt;T&gt;) {
        <span class="kw">return</span> std::vector&lt;T, A&gt;;
    }

    <span class="kw">typename</span> Tuple(<span class="kw">typename</span>... Ts) {
        <span class="kw">return</span> std::tuple&lt;Ts...&gt;;
    }

    <span class="co">// etc.</span></code></pre>
<p>Unifying syntax allows to reusing our composition tools:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    <span class="kw">typename</span> VecOfPtrTuple = Tuple | Ptr | Vector;

    <span class="kw">typename</span> V = VecOfPtrTuple(<span class="dt">int</span>, <span class="dt">bool</span>);
    <span class="kw">static_assert</span>(V == std::vector&lt;std::tuple&lt;<span class="dt">int</span>, <span class="dt">bool</span>&gt;*&gt;);</code></pre>
<p>The difference between type constructors and type functions being semantic, they can be freely mixed:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">  <span class="kw">typename</span> I = IteratorType | VecOfPtrTuple;
  <span class="kw">static_assert</span>(I(<span class="dt">int</span>, <span class="dt">bool</span>) == std::vector&lt;std::tuple&lt;<span class="dt">int</span>, <span class="dt">bool</span>&gt;*&gt;::iterator);</code></pre>
<h2 id="note-on-the-implementation"><a href="#note-on-the-implementation">13. Note on the implementation</a></h2>
<p>This section gives hints to speed up possible implementations. It shows that type functions may be implemented by generating code in terms of other (ongoing) proposals.</p>
<p>The fact that the above examples often look like template specializations doesn't mean that a type function has to be implemented in terms of templates. It may seem more natural to implement it in terms of a <code>constexpr</code> function. For example, the following code where C is a container type:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    IteratorType(C) it;</code></pre>
<p>could result in this generated code (assuming <a href="#p0425">[P0425]</a> features):</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    TYPENAME(__IteratorType(REFLEXPR(C))) it;</code></pre>
<p>The default version of <code>__IteratorType</code> could be roughly implemented in this way:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    std::meta::type __IteratorType(std::meta::type ContainerType) {
        <span class="co">// assuming this notation is valid</span>
        <span class="kw">return</span> ContainerType.inner_typedefs[<span class="st">&quot;iterator&quot;</span>];
    }</code></pre>
<p>Or (assuming <a href="#p0707">[P0707]</a>'s metaclasses), maybe something like:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    __IteratorType($C)$ it;</code></pre>
<p>where <code>__IteratorType</code> is a <code>constexpr</code> function.</p>
<p>The type function <code>IteratorType</code> we previously defined this way:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    ForwardIterator IteratorType(<span class="kw">typename</span> T) {
        <span class="kw">if</span> (Container(T))
            <span class="kw">return</span> T::iterator;
        <span class="kw">typename</span> U;    <span class="co">// declare an unconstrained type</span>
        std::size_t N; <span class="co">// declare an integral constant</span>
                       <span class="co">// for the following pattern-matching.</span>
        <span class="kw">switch</span> (T) {
        <span class="kw">case</span> U[N]:
            <span class="kw">return</span> U*;
        <span class="kw">default</span>:
            fail(<span class="st">&quot;T is neither a container type nor an array type.&quot;</span>);
        }
    }</code></pre>
<p>could lead to this code generation:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    <span class="kw">constexpr</span> <span class="dt">void</span> __IteratorType(meta::type target, <span class="dt">const</span> meta::type source) {
        <span class="kw">if</span> (is_container(t))
            target = t.type(<span class="st">&quot;iterator&quot;</span>);
        <span class="kw">if</span> (is_array(t))
            target = make_pointer(element_type(t));
        fail(<span class="st">&quot;The type is neither a container type nor an array type.&quot;</span>);
    }</code></pre>
<p>Nevertheless, if we have type function overloads, e.g. one <code>IteratorType</code> for container types and another one for array types, having a unique meta-type (<code>meta::type</code>) is not enough. It seems one meta-type per concept would be needed, so that it would be possible to write:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    <span class="co">// Container type overload</span>
    meta::iterator_type __IteratorType(meta::container_type t) {
        <span class="kw">return</span> t.type(<span class="st">&quot;iterator&quot;</span>);
    }

    <span class="co">// Array type overload</span>
    meta::iterator_type __IteratorType(meta::array_type t) {
        <span class="kw">return</span> make_pointer(element_type(t));
    }</code></pre>
<p>Of course, it is also technically possible to generate classical template code:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    <span class="kw">namespace</span> detail {
        <span class="co">// Default case.</span>
        <span class="kw">template</span>&lt;<span class="kw">typename</span> T&gt;
        <span class="kw">struct</span> __IteratorTypeSwitch {
            <span class="co">// T is neither a container type nor an array type.</span>
        };

        <span class="co">// Array type case.</span>
        <span class="kw">template</span>&lt;<span class="kw">typename</span> U, std::size_t N&gt;
        <span class="kw">struct</span> __IteratorTypeSwitch&lt;U [N]&gt; {
            <span class="kw">using</span> type = U*;
        };

        <span class="co">// `T` is a container type.</span>
        <span class="kw">template</span>&lt;<span class="kw">typename</span> T, <span class="dt">bool</span> isContainer&gt;
        <span class="kw">struct</span> __IteratorTypeIfContainer {
            <span class="kw">using</span> type = <span class="kw">typename</span> T::iterator;
        };

        <span class="co">// `T` is _not_ a container type. Continue with the `switch`.</span>
        <span class="kw">template</span>&lt;<span class="kw">typename</span> T&gt;
        <span class="kw">struct</span> __IteratorTypeIfContainer&lt;T, <span class="kw">false</span>&gt; : __IteratorTypeSwitch&lt;T&gt; {
        };
    } <span class="co">// namespace detail</span>

    <span class="co">// Uses `Container` concept.</span>
    <span class="kw">template</span>&lt;<span class="kw">typename</span> T&gt;
    <span class="kw">struct</span> __IteratorType : detail::__IteratorTypeIfContainer&lt;T, Container&lt;T&gt;()&gt; {
    };</code></pre>
<p>Generating code based on meta-types as shown above may be preferable as it avoids template instantiations. Even in this case, type functions allows to:</p>
<ul>
<li>avoid the reflexion / reification juggling</li>
<li>unify syntax between object functions and type functions</li>
<li>resulting in a simpler and more consistent language</li>
</ul>
<p>See <a href="#i.-introduction">introduction</a> for further details.</p>
<p>This also opens the door for further simplifications / unifications as will be shown in the following.</p>
<h1 id="iii.-concept-functions"><a href="#iii.-concept-functions">III. Concept functions</a></h1>
<p>As language entities, concepts should also be manipulable. Below are several examples of concept functions.</p>
<h2 id="optional-and-composition"><a href="#optional-and-composition">1. Optional() and composition</a></h2>
<p>Consider our previous implementation of <code>IteratorType</code>:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    Iterator IteratorType(<span class="kw">typename</span> T) {
        <span class="kw">if</span> (Container(T))  <span class="co">// `Container` is a concept</span>
            <span class="kw">return</span> T::iterator;
        <span class="kw">else</span> <span class="kw">if</span> (Array(T)) <span class="co">// `Array` is a concept</span>
            <span class="kw">return</span> Decay(T);
        fail(<span class="st">&quot;T is neither a container nor an array.&quot;</span>);
    }</code></pre>
<p>It will fail if <code>T</code> is neither a container type nor an array type. This is not desirable in more advanced compositions as we will see below. To avoid failing, we can define a special <code>nil_t</code> type and return it as a fall-back. The problem is the type returned by <code>IteratorType</code> must be an iterator type and <code>nil_t</code> is not. To address this, we first define an <code>Optional</code> concept function with the following definition:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    <span class="kw">struct</span> nil_t {
    };

    <span class="co">// Wrapper to perform specializations (see below).</span>
    <span class="kw">template</span>&lt;<span class="kw">typename</span> T = nil_t&gt;
    <span class="kw">struct</span> opt_t {
    };

    <span class="co">// This is a concept function: it takes a concept and returns another concept.</span>
    concept Optional(concept C) {
        <span class="kw">return</span>
            <span class="kw">template</span>&lt;<span class="kw">typename</span> T&gt;
            concept OptionalC = requires(<span class="kw">typename</span> U) {
                requires T == opt_t&lt;U&gt; &amp;&amp; (U == nil_t || C(U));
            };
    }

    <span class="co">// Alternative assuming it's possible to introduce in-place a type</span>
    <span class="co">// with the syntax `&lt;concept-name&gt;{&lt;type-name&gt;}`:</span>
    concept Optional(concept C) {
        <span class="kw">return</span>
            <span class="kw">typename</span>{T}
            concept OptionalC =
                T == opt_t&lt;<span class="kw">typename</span>{U}&gt; &amp;&amp; (U == nil_t || C(U));
    }</code></pre>
<p>For a concept <code>C</code>, the concept returned by <code>Optional(C)</code> is modeled by all types equal to <code>opt_t</code> parametrized by <code>nil_t</code> or parametrized by a type modeling <code>C</code>.</p>
<p>As a side note, it would be nice to be able to omit the name of the returned concept (<code>OptionalC</code>) since it is not really needed, and simply write:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">        <span class="kw">return</span>
            <span class="kw">typename</span>{T}
            concept =
                T == opt_t&lt;<span class="kw">typename</span>{U}&gt; &amp;&amp; (U == nil_t || C(U));</code></pre>
<p>We can now write a total version of <code>IteratorType</code> (a total function is defined for every value of its domain, i.e. for any input argument):</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    Optional(Iterator) SafeIteratorType(<span class="kw">typename</span> T) {
        <span class="kw">if</span> (Container(T))  <span class="co">// `Container` is a concept</span>
            <span class="kw">return</span> opt_t&lt;T::iterator&gt;;
        <span class="kw">else</span> <span class="kw">if</span> (Array(T)) <span class="co">// `Array` is a concept</span>
            <span class="kw">return</span> opt_t&lt;Decay(T)&gt;;
        <span class="kw">else</span>
            <span class="kw">return</span> opt_t&lt;&gt;; <span class="co">// wraps `nil_t`</span>
    }</code></pre>
<p>And rewrite <code>IteratorType</code> in terms of <code>SafeIteratorType</code>:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    Iterator IteratorType(<span class="kw">typename</span> T) {
        <span class="kw">switch</span> (SafeIteratorType(T)) {
        <span class="kw">case</span> opt_t&lt;<span class="kw">typename</span>{U}&gt;: <span class="co">// introduce U here</span>
            <span class="kw">if</span> (U != nil_t)
                <span class="kw">return</span> U;
            <span class="co">// go to default case</span>
        <span class="kw">default</span>:
            fail(<span class="st">&quot;Couldn't get the iterator type for &quot;</span> +
                nameof(T)); <span class="co">// for `nameof`, see section 12. a</span>
        }
    }</code></pre>
<p>Let's assume we write <code>SafeCodomainType</code> and <code>SafeValueType</code> in the same way, that is with the following signatures:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    Optional(<span class="kw">typename</span>) SafeCodomainType(<span class="kw">typename</span> T);
    Optional(<span class="kw">typename</span>) SafeValueType(<span class="kw">typename</span> T);</code></pre>
<p>Even if it is possible to compose non-safe versions with the default composition operator:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    TypeFunction F = ValueType | CodomainType | IteratorType;</code></pre>
<p>composing safe versions requires more work:</p>
<ul>
<li>if the result of the previous function is empty (i.e. <code>opt_t&lt;&gt;</code>), do not call the next function but directly return <code>opt_t&lt;&gt;</code></li>
<li>otherwise, extract the type parameter out of <code>opt_t</code> and pass it to the next function</li>
</ul>
<p>We name this kind of compositions &quot;k-compositions&quot; (&quot;k&quot; for &quot;kleisli&quot;) and express it with the following code:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    <span class="co">// `G` and `F` are type functions taking a type and returning an `opt_t`</span>
    TypeFunction KCompose(TypeFunction G, TypeFunction F) {
        <span class="kw">return</span> [=](<span class="kw">typename</span> X) {
            <span class="co">// Apply `F`, and depending on the result apply `G` in a relevant way.</span>
            <span class="kw">return</span> KBind(G, F(X));
        };
    }

    <span class="co">// This is the &quot;k-bind&quot; specialization for `opt_t`:</span>
    <span class="co">// `F` outputs `opt_t` but the type function `G` expects a non-`opt_t` type as input.</span>
    <span class="kw">typename</span> KBind(TypeFunction G, concept(opt_t&lt;<span class="kw">typename</span>{Y}&gt;) T) {
        <span class="kw">if</span> (Y == nil_t) {
            <span class="co">// The previous function produced no result, so we can't call G:</span>
            <span class="co">// just return an empty `opt_t`.</span>
            <span class="kw">return</span> opt_t&lt;&gt;;
        }
        <span class="co">// We have a result so we call `G`.</span>
        <span class="kw">return</span> G(Y);
    }

    <span class="co">// A simple overload to make the code more readable.</span>
    TypeFunction <span class="kw">operator</span>&gt;&gt;(TypeFunction F, TypeFunction G) {
        <span class="kw">return</span> KCompose(G, F);
    }</code></pre>
<p>Now we can compose our safe type functions:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    TypeFunction F = SafeValueType &gt;&gt; SafeCodomainType &gt;&gt; SafeIteratorType;
    <span class="co">// Compare this with the simple composition version:</span>
    <span class="co">// TypeFunction F = ValueType | CodomainType | IteratorType;</span>

    <span class="kw">static_assert</span>(F(list&lt;function&lt;vector&lt;<span class="dt">int</span>&gt; ()&gt;&gt;) == opt_t&lt;vector&lt;<span class="dt">int</span>&gt;::iterator&gt;);

    <span class="co">// Here, `SafeValueType` returns `opt_t&lt;&gt;` because a `std::function` has no value type.</span>
    <span class="kw">static_assert</span>(F(function&lt;vector&lt;<span class="dt">int</span>&gt; ()&gt;) == opt_t&lt;&gt;);

    <span class="co">// Here, `SafeCodomainType` returns `opt_t&lt;&gt;` because a `int` has no codomain type.</span>
    <span class="kw">static_assert</span>(F(list&lt;<span class="dt">int</span>&gt;) == opt_t&lt;&gt;);

    <span class="co">// Here, `SafeIteratorType` returns `opt_t&lt;&gt;` because an `int` has no iterator type.</span>
    <span class="kw">static_assert</span>(F(list&lt;function&lt;<span class="dt">int</span> ()&gt;&gt;) == opt_t&lt;&gt;);</code></pre>
<h2 id="instrumented"><a href="#instrumented">2. Instrumented</a></h2>
<p>When writing algorithms, it is good to test their complexity. We can for example check, for a given call, the number of comparisons.</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    <span class="co">// `value` is a value of type `T`.</span>
    <span class="co">// `tranfo` is a transformation on `T`, i.e. a function taking a `T` and returning a `T`.</span>
    <span class="co">// `is_defined` is a predicate on `T`, i.e. a function taking a `T` and returning a `bool`.</span>
    <span class="co">// (see Elements of Programming, 2.3 Collision Point)</span>
    assert(circular(value, transfo, is_defined));

    <span class="co">// Assert that equality has been called 4 times on `T`.</span>
    <span class="co">// `Operation(T)` is an enumeration type on operations available on `T`</span>
    <span class="co">// (equality, copy, assignment, etc.).</span>
    assert(count&lt;T&gt;(Operation(T)::equal) == <span class="dv">4</span>);

    <span class="co">// Reset the equality count.</span>
    count&lt;T&gt;(Operation(T)::equal) = <span class="dv">0</span>;</code></pre>
<p>If <code>circular</code> requires for <code>value</code> an object of a regular type, the above test requires in fact an &quot;instrumented&quot; regular type. &quot;instrumented&quot; means that <code>T</code> must have an <code>Operation(T)</code> enumeration type and a <code>count</code> function to query how many times a given operation has been performed.</p>
<p>Thus, any concept could be instrumented. We could have <code>InstrumentedRegular</code>, <code>InstrumentedIterator</code> (allowing to ask how many times an iterator has been incremented, for example), <code>InstrumentedContainer</code> (allowing to ask many times an element has been &quot;pushed back&quot;, for example), and so on. <code>Instrumented</code> is really a concept function: it takes a concept and returns an enriched concept with additional constraints.</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    concept Instrumented(concept C) {
        <span class="kw">return</span>
            <span class="kw">typename</span>{T}
            concept InstrumentedC =
                   C(T) <span class="co">// the type `T` must model the concept `C`</span>
                &amp;&amp; requires {
                    <span class="co">// `T` must have an operation enum type</span>
                    <span class="kw">typename</span> Operation(T);
                    requires Enumeration(Operation(T)); <span class="co">// assumes an `Enumeration` concept</span>
                }
                &amp;&amp; requires(Operation(T) op) {
                    <span class="co">// must have a count method</span>
                    { count&lt;T&gt;(op) } -&gt; <span class="dt">int</span>&amp;;
                };
    }</code></pre>
<p>Now we can use <code>Instrumented</code> to transform concepts:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    <span class="co">// Generic function to test a `copy_if` algorithm.</span>
    <span class="kw">template</span>&lt;ForwardIterator I, OutputIterator O, Instrumented(UnaryPredicate) P, Procedure Proc&gt;
    <span class="dt">void</span> test_copy_if_complexity(Proc copy_if, I begin, I end, O out, P pred) {
        <span class="dt">auto</span> <span class="dt">const</span> n = std::distance(begin, end);

        <span class="co">// reset the predicate call count</span>
        count&lt;P&gt;(Operation(P)::call) = <span class="dv">0</span>;

        <span class="co">// call `copy_if`</span>
        copy_if(begin, end, out, pred);

        <span class="co">// check that the predicate has been called the expected number of times</span>
        assert(count&lt;P&gt;(Operation(P)::call) == n);
    }</code></pre>
<p>Of course, concept functions are composable. If it makes sense in our context, we could write for example:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    <span class="kw">template</span>&lt;Optional(Instrumented(UnaryPredicate)) P&gt;
    ...</code></pre>
<p>Also inside a concept function, a simpler example of creating a new concept is by using conjunction. Consider the concept <code>Serialize</code>:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    <span class="kw">template</span>&lt;<span class="kw">typename</span> T&gt;
    concept Serialize = requires(T <span class="dt">const</span>&amp; t, std::ostream&amp; o) {
        { serialize(t, o) } -&gt; std::ostream&amp;;
    };</code></pre>
<p>We can define a new concept by &quot;and-ing&quot; two concepts:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    <span class="co">// Adds the `Serialize` constraints.</span>
    concept Serializable(concept C) {
        <span class="kw">return</span> C &amp;&amp; Serialize;
    };

    <span class="co">// Now we can write:</span>
    <span class="kw">template</span>&lt;Instrumented(Serializable(Container)) C&gt;
    ...</code></pre>
<p><code>Serializable</code> is expressed as a concept function because any concept could be serializable: <code>Serializable(Container)</code>, <code>Serializable(Arithmetic)</code>, etc.</p>
<p>In <a href="#c.-logical-operators">section 10. c</a>, we wrote <code>ComplementType</code> with the following signature:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    Predicate ComplementType(Predicate P) requires Class(P) {
        ...
    }</code></pre>
<p>We can now rewrite it as:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    Predicate ComplementType((Predicate &amp;&amp; Class) P) {
        ...
    }</code></pre>
<p>Or we can acknowledge that any concept could be required to only accept a class and use a concept function instead:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    concept AsClass(concept C) {
        <span class="kw">return</span> C &amp;&amp; Class;
    }

    Predicate ComplementType(AsClass(Predicate) P) {
        ...
    }</code></pre>
<p>Of course, disjunction can also be used to create concepts. For example in the following, the regex replacement can be specified as a string pattern or as a function object:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    <span class="co">// Assumes `String` and `FunctionObject` concepts.</span>
    <span class="kw">template</span>&lt;Range Rng, Regex Rgx, (String || FunctionObject) Rpl&gt;
    Predicate regex_replace(Rng rng, Rgx rgx, Rpl replace) {</code></pre>
<p>This leads to the topic of composition. We now compose concept functions. We assume lambdas can be extended to do this job. The exact nature of <code>ConceptFunction</code> is to be investigated. For now, let's assume it just works:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    <span class="co">// Compose two concept functions.</span>
    ConceptFunction Compose(ConceptFunction G, ConceptFunction F) {
        <span class="kw">return</span> [=](concept X) {
            <span class="kw">return</span> G(F(X));
        };
    }</code></pre>
<p>That could be used in the expected way to produce new concept functions:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    concept InstrumentedSerializableClass = Compose(Instrumented, Compose(Serializable, AsClass));

    <span class="kw">template</span>&lt;Procedure Proc, InstrumentedSerializableClass(Container) C&gt;
    <span class="dt">void</span> test_my_algo(Proc p, C c) {
        <span class="co">// ...</span>
    }</code></pre>
<p>We have the same potential readability problem as with type functions, so we can introduce an operator:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    ConceptFunction <span class="kw">operator</span>|(ConceptFunction F, ConceptFunction G) {
        <span class="kw">return</span> Compose(G, F);
    }

    <span class="co">// And we can now alternatively write:</span>
    concept InstrumentedSerializableClass = AsClass | Serializable | Instrumented;</code></pre>
<h1 id="iv.-further-considerations"><a href="#iv.-further-considerations">IV. Further considerations</a></h1>
<h2 id="opportunity-for-unification"><a href="#opportunity-for-unification">1. Opportunity for unification</a></h2>
<p>In the course of this paper, we strove to express similar ideas with similar syntaxes. For example, regardless of the nature of manipulated elements (objects, types...) we expressed:</p>
<ul>
<li>equality with <code>==</code></li>
<li>assignment with <code>=</code></li>
<li>association between elements with functions, lambdas and operators</li>
<li>conditional with <code>if</code></li>
<li>case matching with <code>switch case</code></li>
<li>loop with <code>for</code></li>
</ul>
<p>This makes code easy to read and understand. This makes the language simpler, easier to learn and more powerful. Any kind of entities introduced in the language (types, concepts...) should be checked against these manipulation patterns and these manipulation patterns should be expressed with syntaxes as close as possible.</p>
<p>Once syntax has been unified, new doors for unification open. For example, notice the similarity between object function composition, type function composition and concept function composition:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    <span class="co">// Object function composition</span>
    <span class="kw">template</span>&lt;FunctionObject G, FunctionObject F&gt;
    <span class="dt">auto</span> compose(G g, F f) {
        <span class="kw">return</span> [=](<span class="dt">auto</span> x) {
            <span class="kw">return</span> g(f(x));
        };
    }

    <span class="co">// Type function composition</span>
    TypeFunction Compose(TypeFunction G, TypeFunction F) {
        <span class="kw">return</span> [=](<span class="kw">typename</span> X) {
            <span class="kw">return</span> G(F(X));
        };
    }

    <span class="co">// Concept function composition.</span>
    ConceptFunction Compose(ConceptFunction G, ConceptFunction F) {
        <span class="kw">return</span> [=](concept X) {
            <span class="kw">return</span> G(F(X));
        };
    }</code></pre>
<p>If we had a mechanism to specify that a function can accept anything (objects, types, concepts), we could write a single version. Let's assume that <code>@</code> denotes anything (object, type, concept), this would result in:</p>
<pre class="sourceCode cpp"><code class="sourceCode cpp">    @ compose(@ g, @ f) {
        <span class="kw">return</span> [=](@ x) {
            <span class="kw">return</span> g(f(x));
        };
    }

    <span class="dt">auto</span> real = [](<span class="dt">auto</span> <span class="dt">const</span>&amp; complex) {<span class="kw">return</span> complex.real();};

    <span class="co">// Composition of object functions.</span>
    <span class="dt">auto</span> abs_of_real = compose(abs, real);

    <span class="co">// Composition of type functions.</span>
    <span class="kw">typename</span> ValueTypeOfCodomainType = compose(ValueType, CodomainType);

    <span class="co">// Composition of concept functions.</span>
    concept OptionalSerializable = compose(Optional, Serializable);</code></pre>
<h2 id="on-metaprogramming"><a href="#on-metaprogramming">2. On metaprogramming</a></h2>
<p>In this paper, we tried to unify manipulation of objects, manipulation of types and manipulation of concepts. Each of these happens at a different compilation stage. A schema of these stages could be:</p>
<pre><code>token manipulation stage (preprocessor) -&gt; concept manipulation stage -&gt;
type manipulation stage -&gt; object manipulation stage (runtime)</code></pre>
<p>This is a pipeline and we could imagine adding more customization stages (a bit in the same way as the rendering pipeline on GPU got progressively more stages).</p>
<p>By adding the appropriate manipulation patterns (equality, functions, conditional...) for entities of each stage (preprocessor tokens, concepts, types, objects...), we do not negate the nature of each kind of entities: a concept is a concept, it is different from a type, which is different from a value. We only emphasize the similarity of manipulations.</p>
<p>This is the path of generic programming (in the STL sense): a generic template function does not try to convert its inputs to a common representation (by type-erasing them for example) but simply leverages the similarity of families of types in terms of syntax, semantics and space and time complexity.</p>
<p>A contrario with &quot;meta types&quot;, we lower any entity to the object level. A type becomes a <code>meta::type</code> object, a concept could become a <code>meta::concept</code> object, etc. In a sense we are negating entities' nature, squashing any of them into objects, then manipulating them in this new form, and finally converting them back to their original form.</p>
<p>We believe the generic approach of this document is more natural. Still, the question of data structures arise. What should be the data structures for types? for concepts? We saw that type-for-loops rely on a kind of forward list to iterate. Is this data structure sufficient? In all probability, other data structures should be provided, in the same way some are adapted to the <code>constexpr</code> context.</p>
<p>Nevertheless, these considerations should not hide the fact that as a first step, being able to manipulate types in much the same way as objects would be a great language improvement. To attain more quickly this goal, one lead could be to consider the type function notation as a front-end to a &quot;meta-type&quot; implementation (see <a href="#note-on-the-implementation">implementation section</a>. This way, we would have both ease of manipulation and a reasonable implementation complexity.</p>
<h1 id="v.-acknowledgements"><a href="#v.-acknowledgements">V. Acknowledgements</a></h1>
<p>Thanks to J. Lamotte for his review.</p>
<h1 id="vi.-references"><a href="#vi.-references">VI. References</a></h1>
<h2 id="elements-of-programming"><a href="#elements-of-programming">[Elements of Programming] Alexander Stepanov &amp; Paul McJones, 2009, Addison-Wesley</a></h2>
<p><a href="http://www.elementsofprogramming.com">http://www.elementsofprogramming.com</a></p>
<h2 id="boost-hana"><a href="#boost-hana">[Boost.Hana] Louis Dionne, <em>Hana</em></a></h2>
<p><a href="https://github.com/boostorg/hana">https://github.com/boostorg/hana</a></p>
<h2 id="p0425"><a href="#p0425">[P0425] Louis Dionne, <em>Metaprogramming by design, not by accident</em></a></h2>
<p><a href="http://open-std.org/JTC1/SC22/WG21/docs/papers/2017/p0425r0.pdf">http://open-std.org/JTC1/SC22/WG21/docs/papers/2017/p0425r0.pdf</a></p>
<h2 id="p0707"><a href="#p0707">[P0707] Herb Sutter, <em>Metaclasses: Generative C++</em></a></h2>
<p><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0707r3.pdf">http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0707r3.pdf</a></p>
<h2 id="p0343"><a href="#p0343">[P0343] Vicente J. Botet Escribá, <em>Meta-programming High-Order functions</em></a></h2>
<p><a href="http://open-std.org/JTC1/SC22/WG21/docs/papers/2017/p0343r1.pdf">http://open-std.org/JTC1/SC22/WG21/docs/papers/2017/p0343r1.pdf</a></p>
<h2 id="cppreference"><a href="#cppreference">[cppreference.com] Constraints and concepts</a></h2>
<p><a href="http://en.cppreference.com/mwiki/index.php?title=cpp/language/constraints">http://en.cppreference.com/mwiki/index.php?title=cpp/language/constraints</a></p>
<h2 id="p0694"><a href="#p0694">[P0694] Bjarne Stroustrup, <em>Function declarations using concepts</em></a></h2>
<p><a href="http://open-std.org/JTC1/SC22/WG21/docs/papers/2017/p0694r0.pdf">http://open-std.org/JTC1/SC22/WG21/docs/papers/2017/p0694r0.pdf</a></p>
<h2 id="p0095"><a href="#p0095">[P0095] David Sankel, <em>Pattern Matching and Language Variants</em></a></h2>
<p><a href="http://open-std.org/JTC1/SC22/WG21/docs/papers/2016/p0095r1.html">http://open-std.org/JTC1/SC22/WG21/docs/papers/2016/p0095r1.html</a></p>
</body>
</html>
