1
0
forked from boostorg/mp11

Add examples to documentation.

This commit is contained in:
Peter Dimov
2017-03-17 05:55:27 +02:00
parent 98c9595bf4
commit 077d46820f
4 changed files with 462 additions and 55 deletions

View File

@@ -33,9 +33,16 @@
<p><b>Table of Contents</b></p> <p><b>Table of Contents</b></p>
<dl class="toc"> <dl class="toc">
<dt><span class="section"><a href="mp11.html#mp11.overview">Overview</a></span></dt> <dt><span class="section"><a href="mp11.html#mp11.overview">Overview</a></span></dt>
<dt><span class="section"><a href="mp11.html#mp11.definitions">Definitions</a></span></dt>
<dt><span class="section"><a href="mp11.html#mp11.examples">Examples</a></span></dt>
<dd><dl>
<dt><span class="section"><a href="mp11.html#mp11.examples.generating_test_cases">Generating Test
Cases</a></span></dt>
<dt><span class="section"><a href="mp11.html#mp11.examples.computing_return_types">Computing Return
Types</a></span></dt>
</dl></dd>
<dt><span class="section"><a href="mp11.html#mp11.reference">Reference</a></span></dt> <dt><span class="section"><a href="mp11.html#mp11.reference">Reference</a></span></dt>
<dd><dl> <dd><dl>
<dt><span class="section"><a href="mp11.html#mp11.reference.definitions">Definitions</a></span></dt>
<dt><span class="section"><a href="mp11.html#mp11.reference.integral">Integral Constants, <code class="computeroutput"><span class="special">&lt;</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">mp11</span><span class="special">/</span><span class="identifier">integral</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span></code></a></span></dt> <dt><span class="section"><a href="mp11.html#mp11.reference.integral">Integral Constants, <code class="computeroutput"><span class="special">&lt;</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">mp11</span><span class="special">/</span><span class="identifier">integral</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span></code></a></span></dt>
<dd><dl> <dd><dl>
<dt><span class="section"><a href="mp11.html#mp11.reference.integral.mp_bool_b"><code class="computeroutput"><span class="identifier">mp_bool</span><span class="special">&lt;</span><span class="identifier">B</span><span class="special">&gt;</span></code></a></span></dt> <dt><span class="section"><a href="mp11.html#mp11.reference.integral.mp_bool_b"><code class="computeroutput"><span class="identifier">mp_bool</span><span class="special">&lt;</span><span class="identifier">B</span><span class="special">&gt;</span></code></a></span></dt>
@@ -175,7 +182,7 @@
<code class="computeroutput"><span class="identifier">mp_list</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">...&gt;</span></code> <code class="computeroutput"><span class="identifier">mp_list</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">...&gt;</span></code>
is the built-in list type, but <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">tuple</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">...&gt;</span></code>, is the built-in list type, but <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">tuple</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">...&gt;</span></code>,
<code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">pair</span><span class="special">&lt;</span><span class="identifier">T1</span><span class="special">,</span> <span class="identifier">T2</span><span class="special">&gt;</span></code> and <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">variant</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">...&gt;</span></code> <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">pair</span><span class="special">&lt;</span><span class="identifier">T1</span><span class="special">,</span> <span class="identifier">T2</span><span class="special">&gt;</span></code> and <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">variant</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">...&gt;</span></code>
are also perfectly legitimate list types, although of course <code class="computeroutput"><span class="identifier">std</span><span class="special">:</span><span class="identifier">pair</span><span class="special">&lt;</span><span class="identifier">T1</span><span class="special">,</span> are also perfectly legitimate list types, although of course <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">pair</span><span class="special">&lt;</span><span class="identifier">T1</span><span class="special">,</span>
<span class="identifier">T2</span><span class="special">&gt;</span></code>, <span class="identifier">T2</span><span class="special">&gt;</span></code>,
due to having exactly two elements, is not resizeable and will consequently due to having exactly two elements, is not resizeable and will consequently
not work with algorithms that need to add or remove elements. not work with algorithms that need to add or remove elements.
@@ -184,10 +191,11 @@
Another distinguishing feature of this approach is that lists (<code class="computeroutput"><span class="identifier">L</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">...&gt;</span></code>) have the same form as metafunctions Another distinguishing feature of this approach is that lists (<code class="computeroutput"><span class="identifier">L</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">...&gt;</span></code>) have the same form as metafunctions
(<code class="computeroutput"><span class="identifier">F</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">...&gt;</span></code>) (<code class="computeroutput"><span class="identifier">F</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">...&gt;</span></code>)
and can therefore be used as such. For example, applying <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">add_pointer_t</span></code> and can therefore be used as such. For example, applying <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">add_pointer_t</span></code>
to the list <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">tuple</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">,</span> <span class="keyword">float</span><span class="special">&gt;</span></code> by way of <code class="computeroutput"><span class="identifier">mp_transform</span><span class="special">&lt;</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">tuple</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">,</span> <span class="keyword">float</span><span class="special">&gt;,</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">add_pointer_t</span><span class="special">&gt;</span></code> gives us <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">tuple</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">*,</span> <span class="keyword">float</span><span class="special">*&gt;</span></code>, but we can also apply <code class="computeroutput"><span class="identifier">mp_list</span></code> to the list <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">tuple</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">,</span> <span class="keyword">float</span><span class="special">&gt;</span></code> by way of <code class="computeroutput"><span class="identifier">mp_transform</span><span class="special">&lt;</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">add_pointer_t</span><span class="special">,</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">tuple</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">,</span> <span class="keyword">float</span><span class="special">&gt;&gt;</span></code> gives us <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">tuple</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">*,</span> <span class="keyword">float</span><span class="special">*&gt;</span></code>, but we can also apply <code class="computeroutput"><span class="identifier">mp_list</span></code>
to the same tuple: to the same tuple:
</p> </p>
<pre class="programlisting"><span class="keyword">using</span> <span class="identifier">R</span> <span class="special">=</span> <span class="identifier">mp_transform</span><span class="special">&lt;</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">tuple</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">,</span> <span class="keyword">float</span><span class="special">&gt;,</span> <span class="identifier">mp_list</span><span class="special">&gt;;</span> <pre class="programlisting"><span class="keyword">using</span> <span class="identifier">R</span> <span class="special">=</span> <span class="identifier">mp_transform</span><span class="special">&lt;</span><span class="identifier">mp_list</span><span class="special">,</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">tuple</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">,</span> <span class="keyword">float</span><span class="special">&gt;&gt;;</span>
</pre> </pre>
<p> <p>
and get <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">tuple</span><span class="special">&lt;</span><span class="identifier">mp_list</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">&gt;,</span> <span class="identifier">mp_list</span><span class="special">&lt;</span><span class="keyword">float</span><span class="special">&gt;&gt;</span></code>. and get <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">tuple</span><span class="special">&lt;</span><span class="identifier">mp_list</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">&gt;,</span> <span class="identifier">mp_list</span><span class="special">&lt;</span><span class="keyword">float</span><span class="special">&gt;&gt;</span></code>.
@@ -195,16 +203,8 @@
</div> </div>
<div class="section"> <div class="section">
<div class="titlepage"><div><div><h2 class="title" style="clear: both"> <div class="titlepage"><div><div><h2 class="title" style="clear: both">
<a name="mp11.reference"></a><a class="link" href="mp11.html#mp11.reference" title="Reference">Reference</a> <a name="mp11.definitions"></a><a class="link" href="mp11.html#mp11.definitions" title="Definitions">Definitions</a>
</h2></div></div></div> </h2></div></div></div>
<p>
The contents of the library are in namespace <code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">mp11</span></code>, unless
specified otherwise.
</p>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="mp11.reference.definitions"></a><a class="link" href="mp11.html#mp11.reference.definitions" title="Definitions">Definitions</a>
</h3></div></div></div>
<p> <p>
A <span class="emphasis"><em>list</em></span> is a &#8212; possibly but not necessarily variadic &#8212; template A <span class="emphasis"><em>list</em></span> is a &#8212; possibly but not necessarily variadic &#8212; template
class whose parameters are all types, for example <code class="computeroutput"><span class="identifier">mp_list</span><span class="special">&lt;</span><span class="keyword">char</span><span class="special">[],</span> class whose parameters are all types, for example <code class="computeroutput"><span class="identifier">mp_list</span><span class="special">&lt;</span><span class="keyword">char</span><span class="special">[],</span>
@@ -235,8 +235,8 @@
</pre> </pre>
<p> <p>
An <span class="emphasis"><em>integral constant type</em></span> is a class with a public member An <span class="emphasis"><em>integral constant type</em></span> is a class with a public member
<code class="computeroutput"><span class="identifier">value</span></code> that is an integral <code class="computeroutput"><span class="identifier">value</span></code> that is an integral constant
constant in the C++ sense. For example, <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">integral_constant</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">,</span> in the C++ sense. For example, <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">integral_constant</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">,</span>
<span class="number">7</span><span class="special">&gt;</span></code>, <span class="number">7</span><span class="special">&gt;</span></code>,
or or
</p> </p>
@@ -244,6 +244,237 @@
</pre> </pre>
</div> </div>
<div class="section"> <div class="section">
<div class="titlepage"><div><div><h2 class="title" style="clear: both">
<a name="mp11.examples"></a><a class="link" href="mp11.html#mp11.examples" title="Examples">Examples</a>
</h2></div></div></div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="mp11.examples.generating_test_cases"></a><a class="link" href="mp11.html#mp11.examples.generating_test_cases" title="Generating Test Cases">Generating Test
Cases</a>
</h3></div></div></div>
<p>
Let's suppose that we have written a metafunction <code class="computeroutput"><span class="identifier">result</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">,</span>
<span class="identifier">U</span><span class="special">&gt;</span></code>:
</p>
<pre class="programlisting"><span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">class</span> <span class="identifier">T</span><span class="special">&gt;</span> <span class="keyword">using</span> <span class="identifier">promote</span> <span class="special">=</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">common_type_t</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">,</span> <span class="keyword">int</span><span class="special">&gt;;</span>
<span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">class</span> <span class="identifier">T</span><span class="special">,</span> <span class="keyword">class</span> <span class="identifier">U</span><span class="special">&gt;</span> <span class="keyword">using</span> <span class="identifier">result</span> <span class="special">=</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">common_type_t</span><span class="special">&lt;</span><span class="identifier">promote</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">&gt;,</span> <span class="identifier">promote</span><span class="special">&lt;</span><span class="identifier">U</span><span class="special">&gt;&gt;;</span>
</pre>
<p>
that ought to represent the result of an arithmetic operation on the integer
types <code class="computeroutput"><span class="identifier">T</span></code> and <code class="computeroutput"><span class="identifier">U</span></code>, for example <code class="computeroutput"><span class="identifier">t</span>
<span class="special">+</span> <span class="identifier">u</span></code>.
We want to test whether <code class="computeroutput"><span class="identifier">result</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">,</span>
<span class="identifier">U</span><span class="special">&gt;</span></code>
gives correct results for various combinations of <code class="computeroutput"><span class="identifier">T</span></code>
and <code class="computeroutput"><span class="identifier">U</span></code>, so we write the function
</p>
<pre class="programlisting"><span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">class</span> <span class="identifier">T1</span><span class="special">,</span> <span class="keyword">class</span> <span class="identifier">T2</span><span class="special">&gt;</span> <span class="keyword">void</span> <span class="identifier">test_result</span><span class="special">()</span>
<span class="special">{</span>
<span class="keyword">using</span> <span class="identifier">T3</span> <span class="special">=</span> <span class="keyword">decltype</span><span class="special">(</span> <span class="identifier">T1</span><span class="special">()</span> <span class="special">+</span> <span class="identifier">T2</span><span class="special">()</span> <span class="special">);</span>
<span class="keyword">using</span> <span class="identifier">T4</span> <span class="special">=</span> <span class="identifier">result</span><span class="special">&lt;</span><span class="identifier">T1</span><span class="special">,</span> <span class="identifier">T2</span><span class="special">&gt;;</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="special">(</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">is_same</span><span class="special">&lt;</span><span class="identifier">T3</span><span class="special">,</span> <span class="identifier">T4</span><span class="special">&gt;::</span><span class="identifier">value</span><span class="special">?</span> <span class="string">"[PASS]"</span><span class="special">:</span> <span class="string">"[FAIL]"</span> <span class="special">)</span> <span class="special">&lt;&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
<span class="special">}</span>
</pre>
<p>
and then need to call it a substantial number of times:
</p>
<pre class="programlisting"><span class="keyword">int</span> <span class="identifier">main</span><span class="special">()</span>
<span class="special">{</span>
<span class="identifier">test_result</span><span class="special">&lt;</span><span class="keyword">char</span><span class="special">,</span> <span class="keyword">char</span><span class="special">&gt;();</span>
<span class="identifier">test_result</span><span class="special">&lt;</span><span class="keyword">char</span><span class="special">,</span> <span class="keyword">short</span><span class="special">&gt;();</span>
<span class="identifier">test_result</span><span class="special">&lt;</span><span class="keyword">char</span><span class="special">,</span> <span class="keyword">int</span><span class="special">&gt;();</span>
<span class="identifier">test_result</span><span class="special">&lt;</span><span class="keyword">char</span><span class="special">,</span> <span class="keyword">unsigned</span><span class="special">&gt;();</span>
<span class="comment">// ...</span>
<span class="special">}</span>
</pre>
<p>
Writing all those type combinations by hand is unwieldy, error prone, and
worst of all, boring. This is how we can leverage Mp11 to automate the task:
</p>
<pre class="programlisting"><span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">mp11</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span>
<span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">tuple_for_each</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span>
<span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">core</span><span class="special">/</span><span class="identifier">demangle</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span>
<span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">type_traits</span><span class="special">&gt;</span>
<span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">iostream</span><span class="special">&gt;</span>
<span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">typeinfo</span><span class="special">&gt;</span>
<span class="keyword">using</span> <span class="keyword">namespace</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">mp11</span><span class="special">;</span>
<span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">class</span> <span class="identifier">T</span><span class="special">&gt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="identifier">name</span><span class="special">()</span>
<span class="special">{</span>
<span class="keyword">return</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">core</span><span class="special">::</span><span class="identifier">demangle</span><span class="special">(</span> <span class="keyword">typeid</span><span class="special">(</span><span class="identifier">T</span><span class="special">).</span><span class="identifier">name</span><span class="special">()</span> <span class="special">);</span>
<span class="special">}</span>
<span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">class</span> <span class="identifier">T</span><span class="special">&gt;</span> <span class="keyword">using</span> <span class="identifier">promote</span> <span class="special">=</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">common_type_t</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">,</span> <span class="keyword">int</span><span class="special">&gt;;</span>
<span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">class</span> <span class="identifier">T</span><span class="special">,</span> <span class="keyword">class</span> <span class="identifier">U</span><span class="special">&gt;</span> <span class="keyword">using</span> <span class="identifier">result</span> <span class="special">=</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">common_type_t</span><span class="special">&lt;</span><span class="identifier">promote</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">&gt;,</span> <span class="identifier">promote</span><span class="special">&lt;</span><span class="identifier">U</span><span class="special">&gt;&gt;;</span>
<span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">class</span> <span class="identifier">T1</span><span class="special">,</span> <span class="keyword">class</span> <span class="identifier">T2</span><span class="special">&gt;</span> <span class="keyword">void</span> <span class="identifier">test_result</span><span class="special">(</span> <span class="identifier">mp_list</span><span class="special">&lt;</span><span class="identifier">T1</span><span class="special">,</span> <span class="identifier">T2</span><span class="special">&gt;</span> <span class="keyword">const</span><span class="special">&amp;</span> <span class="special">)</span>
<span class="special">{</span>
<span class="keyword">using</span> <span class="identifier">T3</span> <span class="special">=</span> <span class="keyword">decltype</span><span class="special">(</span> <span class="identifier">T1</span><span class="special">()</span> <span class="special">+</span> <span class="identifier">T2</span><span class="special">()</span> <span class="special">);</span>
<span class="keyword">using</span> <span class="identifier">T4</span> <span class="special">=</span> <span class="identifier">result</span><span class="special">&lt;</span><span class="identifier">T1</span><span class="special">,</span> <span class="identifier">T2</span><span class="special">&gt;;</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="special">(</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">is_same</span><span class="special">&lt;</span><span class="identifier">T3</span><span class="special">,</span> <span class="identifier">T4</span><span class="special">&gt;::</span><span class="identifier">value</span><span class="special">?</span> <span class="string">"[PASS] "</span><span class="special">:</span> <span class="string">"[FAIL] "</span> <span class="special">)</span> <span class="special">&lt;&lt;</span> <span class="identifier">name</span><span class="special">&lt;</span><span class="identifier">T1</span><span class="special">&gt;()</span> <span class="special">&lt;&lt;</span> <span class="string">" + "</span> <span class="special">&lt;&lt;</span> <span class="identifier">name</span><span class="special">&lt;</span><span class="identifier">T2</span><span class="special">&gt;()</span> <span class="special">&lt;&lt;</span> <span class="string">" -&gt; "</span> <span class="special">&lt;&lt;</span> <span class="identifier">name</span><span class="special">&lt;</span><span class="identifier">T3</span><span class="special">&gt;()</span> <span class="special">&lt;&lt;</span> <span class="string">", result: "</span> <span class="special">&lt;&lt;</span> <span class="identifier">name</span><span class="special">&lt;</span><span class="identifier">T4</span><span class="special">&gt;()</span> <span class="special">&lt;&lt;</span> <span class="string">" "</span> <span class="special">&lt;&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
<span class="special">}</span>
<span class="keyword">int</span> <span class="identifier">main</span><span class="special">()</span>
<span class="special">{</span>
<span class="keyword">using</span> <span class="identifier">L</span> <span class="special">=</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">tuple</span><span class="special">&lt;</span><span class="keyword">char</span><span class="special">,</span> <span class="keyword">short</span><span class="special">,</span> <span class="keyword">int</span><span class="special">,</span> <span class="keyword">unsigned</span><span class="special">,</span> <span class="keyword">long</span><span class="special">,</span> <span class="keyword">unsigned</span> <span class="keyword">long</span><span class="special">&gt;;</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">tuple_for_each</span><span class="special">(</span> <span class="identifier">mp_product</span><span class="special">&lt;</span><span class="identifier">mp_list</span><span class="special">,</span> <span class="identifier">L</span><span class="special">,</span> <span class="identifier">L</span><span class="special">&gt;(),</span> <span class="special">[](</span><span class="keyword">auto</span><span class="special">&amp;&amp;</span> <span class="identifier">x</span><span class="special">){</span> <span class="identifier">test_result</span><span class="special">(</span><span class="identifier">x</span><span class="special">);</span> <span class="special">}</span> <span class="special">);</span>
<span class="special">}</span>
</pre>
</div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="mp11.examples.computing_return_types"></a><a class="link" href="mp11.html#mp11.examples.computing_return_types" title="Computing Return Types">Computing Return
Types</a>
</h3></div></div></div>
<p>
C++17 has a standard variant type, called <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">variant</span></code>.
It also defines a function template <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">visit</span></code>
that can be used to apply a function to the contained value of one or more
<code class="computeroutput"><span class="identifier">variant</span></code>s. So for instance,
if the <code class="computeroutput"><span class="identifier">variant</span></code> <code class="computeroutput"><span class="identifier">v1</span></code> contains <code class="computeroutput"><span class="number">1</span></code>,
and the <code class="computeroutput"><span class="identifier">variant</span></code> <code class="computeroutput"><span class="identifier">v2</span></code> contains <code class="computeroutput"><span class="number">2.0f</span></code>,
<code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">visit</span><span class="special">(</span><span class="identifier">f</span><span class="special">,</span> <span class="identifier">v1</span><span class="special">,</span> <span class="identifier">v2</span><span class="special">)</span></code>
will call <code class="computeroutput"><span class="identifier">f</span><span class="special">(</span><span class="number">1</span><span class="special">,</span> <span class="number">2.0f</span><span class="special">)</span></code>.
</p>
<p>
However, <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">visit</span></code> has one limitation: it cannot return
a result unless all possible applications of the function have the same return
type. If, for instance, <code class="computeroutput"><span class="identifier">v1</span></code>
and <code class="computeroutput"><span class="identifier">v2</span></code> are both of type
<code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">variant</span><span class="special">&lt;</span><span class="keyword">short</span><span class="special">,</span> <span class="keyword">int</span><span class="special">,</span> <span class="keyword">float</span><span class="special">&gt;</span></code>,
</p>
<pre class="programlisting"><span class="identifier">std</span><span class="special">::</span><span class="identifier">visit</span><span class="special">(</span> <span class="special">[](</span> <span class="keyword">auto</span> <span class="keyword">const</span><span class="special">&amp;</span> <span class="identifier">x</span><span class="special">,</span> <span class="keyword">auto</span> <span class="keyword">const</span><span class="special">&amp;</span> <span class="identifier">y</span> <span class="special">){</span> <span class="keyword">return</span> <span class="identifier">x</span> <span class="special">+</span> <span class="identifier">y</span><span class="special">;</span> <span class="special">},</span> <span class="identifier">v1</span><span class="special">,</span> <span class="identifier">v2</span> <span class="special">);</span>
</pre>
<p>
will fail to compile because the result of <code class="computeroutput"><span class="identifier">x</span>
<span class="special">+</span> <span class="identifier">y</span></code>
can be either <code class="computeroutput"><span class="keyword">int</span></code> or <code class="computeroutput"><span class="keyword">float</span></code> depending on what <code class="computeroutput"><span class="identifier">v1</span></code>
and <code class="computeroutput"><span class="identifier">v2</span></code> hold.
</p>
<p>
A type that can hold either <code class="computeroutput"><span class="keyword">int</span></code>
or <code class="computeroutput"><span class="keyword">float</span></code> already exists, called,
surprisingly enough, <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">variant</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">,</span>
<span class="keyword">float</span><span class="special">&gt;</span></code>.
Let's write our own function template <code class="computeroutput"><span class="identifier">rvisit</span></code>
that is the same as <code class="computeroutput"><span class="identifier">visit</span></code>
but returns a <code class="computeroutput"><span class="identifier">variant</span></code>:
</p>
<pre class="programlisting"><span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">class</span> <span class="identifier">F</span><span class="special">,</span> <span class="keyword">class</span><span class="special">...</span> <span class="identifier">V</span><span class="special">&gt;</span> <span class="keyword">auto</span> <span class="identifier">rvisit</span><span class="special">(</span> <span class="identifier">F</span><span class="special">&amp;&amp;</span> <span class="identifier">f</span><span class="special">,</span> <span class="identifier">V</span><span class="special">&amp;&amp;...</span> <span class="identifier">v</span> <span class="special">)</span>
<span class="special">{</span>
<span class="keyword">using</span> <span class="identifier">R</span> <span class="special">=</span> <span class="comment">/*...*/</span><span class="special">;</span>
<span class="keyword">return</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">visit</span><span class="special">(</span> <span class="special">[&amp;](</span> <span class="keyword">auto</span><span class="special">&amp;&amp;...</span> <span class="identifier">x</span> <span class="special">){</span> <span class="keyword">return</span> <span class="identifier">R</span><span class="special">(</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">forward</span><span class="special">&lt;</span><span class="identifier">F</span><span class="special">&gt;(</span><span class="identifier">f</span><span class="special">)(</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">forward</span><span class="special">&lt;</span><span class="keyword">decltype</span><span class="special">(</span><span class="identifier">x</span><span class="special">)&gt;(</span><span class="identifier">x</span><span class="special">)...</span> <span class="special">)</span> <span class="special">);</span> <span class="special">},</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">forward</span><span class="special">&lt;</span><span class="identifier">V</span><span class="special">&gt;(</span> <span class="identifier">v</span> <span class="special">)...</span> <span class="special">);</span>
<span class="special">}</span>
</pre>
<p>
What this does is basically calls <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">visit</span></code>
to do the work, but instead of passing it <code class="computeroutput"><span class="identifier">f</span></code>,
we pass a lambda that does the same as <code class="computeroutput"><span class="identifier">f</span></code>
except it converts the result to a common type <code class="computeroutput"><span class="identifier">R</span></code>.
<code class="computeroutput"><span class="identifier">R</span></code> is supposed to be <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">variant</span><span class="special">&lt;...&gt;</span></code> where the ellipsis denotes the
return types of calling <code class="computeroutput"><span class="identifier">f</span></code>
with all possible combinations of variant values.
</p>
<p>
We'll first define a helper quoted metafunction <code class="computeroutput"><span class="identifier">Qret</span><span class="special">&lt;</span><span class="identifier">F</span><span class="special">&gt;</span></code>
that returns the result of the application of <code class="computeroutput"><span class="identifier">F</span></code>
to arguments of type <code class="computeroutput"><span class="identifier">T</span><span class="special">...</span></code>:
</p>
<pre class="programlisting"><span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">class</span> <span class="identifier">F</span><span class="special">&gt;</span> <span class="keyword">struct</span> <span class="identifier">Qret</span>
<span class="special">{</span>
<span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">class</span><span class="special">...</span> <span class="identifier">T</span><span class="special">&gt;</span> <span class="keyword">using</span> <span class="identifier">invoke</span> <span class="special">=</span> <span class="keyword">decltype</span><span class="special">(</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">declval</span><span class="special">&lt;</span><span class="identifier">F</span><span class="special">&gt;()(</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">declval</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">&gt;()...</span> <span class="special">)</span> <span class="special">);</span>
<span class="special">};</span>
</pre>
<p>
(Unfortunately, we can't just define this metafunction inside <code class="computeroutput"><span class="identifier">rvisit</span></code>; the language prohibits defining
template aliases inside functions.)
</p>
<p>
With <code class="computeroutput"><span class="identifier">Qret</span></code> in hand, a <code class="computeroutput"><span class="identifier">variant</span></code> of the possible return types is
just a matter of applying it over the possible combinations of the variant
values:
</p>
<pre class="programlisting"><span class="keyword">using</span> <span class="identifier">R</span> <span class="special">=</span> <span class="identifier">mp_product</span><span class="special">&lt;</span><span class="identifier">Qret</span><span class="special">&lt;</span><span class="identifier">F</span><span class="special">&gt;::</span><span class="keyword">template</span> <span class="identifier">invoke</span><span class="special">,</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">remove_reference_t</span><span class="special">&lt;</span><span class="identifier">V</span><span class="special">&gt;...&gt;;</span>
</pre>
<p>
Why does this work? <code class="computeroutput"><span class="identifier">mp_product</span><span class="special">&lt;</span><span class="identifier">F</span><span class="special">,</span>
<span class="identifier">L1</span><span class="special">&lt;</span><span class="identifier">T1</span><span class="special">...&gt;,</span> <span class="identifier">L2</span><span class="special">&lt;</span><span class="identifier">T2</span><span class="special">...&gt;,</span> <span class="special">...,</span> <span class="identifier">Ln</span><span class="special">&lt;</span><span class="identifier">Tn</span><span class="special">...&gt;&gt;</span></code> returns <code class="computeroutput"><span class="identifier">L1</span><span class="special">&lt;</span><span class="identifier">F</span><span class="special">&lt;</span><span class="identifier">U1</span><span class="special">,</span> <span class="identifier">U2</span><span class="special">,</span> <span class="special">...,</span> <span class="identifier">Un</span><span class="special">&gt;,</span> <span class="special">...&gt;</span></code>,
where <code class="computeroutput"><span class="identifier">Ui</span></code> traverse all possible
combinations of list values. Since in our case all <code class="computeroutput"><span class="identifier">Li</span></code>
are <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">variant</span></code>, the result will also be <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">variant</span></code>.
</p>
<p>
One more step remains. Suppose that, as above, we're passing two variants
of type <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">variant</span><span class="special">&lt;</span><span class="keyword">short</span><span class="special">,</span> <span class="keyword">int</span><span class="special">,</span> <span class="keyword">float</span><span class="special">&gt;</span></code>
and <code class="computeroutput"><span class="identifier">F</span></code> is <code class="computeroutput"><span class="special">[](</span>
<span class="keyword">auto</span> <span class="keyword">const</span><span class="special">&amp;</span> <span class="identifier">x</span><span class="special">,</span> <span class="keyword">auto</span> <span class="keyword">const</span><span class="special">&amp;</span> <span class="identifier">y</span> <span class="special">){</span> <span class="keyword">return</span> <span class="identifier">x</span> <span class="special">+</span> <span class="identifier">y</span><span class="special">;</span> <span class="special">}</span></code>. This
will generate <code class="computeroutput"><span class="identifier">R</span></code> of length
9, one per each combination, but many of those elements will be the same,
either <code class="computeroutput"><span class="keyword">int</span></code> or <code class="computeroutput"><span class="keyword">float</span></code>, and we need to filter out the duplicates.
So,
</p>
<pre class="programlisting"><span class="keyword">using</span> <span class="identifier">R</span> <span class="special">=</span> <span class="identifier">mp_unique</span><span class="special">&lt;</span><span class="identifier">mp_product</span><span class="special">&lt;</span><span class="identifier">Qret</span><span class="special">&lt;</span><span class="identifier">F</span><span class="special">&gt;::</span><span class="keyword">template</span> <span class="identifier">invoke</span><span class="special">,</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">remove_reference_t</span><span class="special">&lt;</span><span class="identifier">V</span><span class="special">&gt;...&gt;&gt;;</span>
</pre>
<p>
and we're done:
</p>
<pre class="programlisting"><span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">mp11</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span>
<span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">core</span><span class="special">/</span><span class="identifier">demangle</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span>
<span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">variant</span><span class="special">&gt;</span>
<span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">type_traits</span><span class="special">&gt;</span>
<span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">typeinfo</span><span class="special">&gt;</span>
<span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">iostream</span><span class="special">&gt;</span>
<span class="keyword">using</span> <span class="keyword">namespace</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">mp11</span><span class="special">;</span>
<span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">class</span> <span class="identifier">F</span><span class="special">&gt;</span> <span class="keyword">struct</span> <span class="identifier">Qret</span>
<span class="special">{</span>
<span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">class</span><span class="special">...</span> <span class="identifier">T</span><span class="special">&gt;</span> <span class="keyword">using</span> <span class="identifier">invoke</span> <span class="special">=</span> <span class="keyword">decltype</span><span class="special">(</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">declval</span><span class="special">&lt;</span><span class="identifier">F</span><span class="special">&gt;()(</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">declval</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">&gt;()...</span> <span class="special">)</span> <span class="special">);</span>
<span class="special">};</span>
<span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">class</span> <span class="identifier">F</span><span class="special">,</span> <span class="keyword">class</span><span class="special">...</span> <span class="identifier">V</span><span class="special">&gt;</span> <span class="keyword">auto</span> <span class="identifier">rvisit</span><span class="special">(</span> <span class="identifier">F</span><span class="special">&amp;&amp;</span> <span class="identifier">f</span><span class="special">,</span> <span class="identifier">V</span><span class="special">&amp;&amp;...</span> <span class="identifier">v</span> <span class="special">)</span>
<span class="special">{</span>
<span class="keyword">using</span> <span class="identifier">R</span> <span class="special">=</span> <span class="identifier">mp_unique</span><span class="special">&lt;</span><span class="identifier">mp_product</span><span class="special">&lt;</span><span class="identifier">Qret</span><span class="special">&lt;</span><span class="identifier">F</span><span class="special">&gt;::</span><span class="keyword">template</span> <span class="identifier">invoke</span><span class="special">,</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">remove_reference_t</span><span class="special">&lt;</span><span class="identifier">V</span><span class="special">&gt;...&gt;&gt;;</span>
<span class="keyword">return</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">visit</span><span class="special">(</span> <span class="special">[&amp;](</span> <span class="keyword">auto</span><span class="special">&amp;&amp;...</span> <span class="identifier">x</span> <span class="special">){</span> <span class="keyword">return</span> <span class="identifier">R</span><span class="special">(</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">forward</span><span class="special">&lt;</span><span class="identifier">F</span><span class="special">&gt;(</span><span class="identifier">f</span><span class="special">)(</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">forward</span><span class="special">&lt;</span><span class="keyword">decltype</span><span class="special">(</span><span class="identifier">x</span><span class="special">)&gt;(</span><span class="identifier">x</span><span class="special">)...</span> <span class="special">)</span> <span class="special">);</span> <span class="special">},</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">forward</span><span class="special">&lt;</span><span class="identifier">V</span><span class="special">&gt;(</span> <span class="identifier">v</span> <span class="special">)...</span> <span class="special">);</span>
<span class="special">}</span>
<span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">class</span> <span class="identifier">T</span><span class="special">&gt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="identifier">name</span><span class="special">()</span>
<span class="special">{</span>
<span class="keyword">return</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">core</span><span class="special">::</span><span class="identifier">demangle</span><span class="special">(</span> <span class="keyword">typeid</span><span class="special">(</span><span class="identifier">T</span><span class="special">).</span><span class="identifier">name</span><span class="special">()</span> <span class="special">);</span>
<span class="special">}</span>
<span class="keyword">int</span> <span class="identifier">main</span><span class="special">()</span>
<span class="special">{</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">variant</span><span class="special">&lt;</span><span class="keyword">signed</span> <span class="keyword">char</span><span class="special">,</span> <span class="keyword">unsigned</span> <span class="keyword">char</span><span class="special">,</span> <span class="keyword">signed</span> <span class="keyword">short</span><span class="special">,</span> <span class="keyword">unsigned</span> <span class="keyword">short</span><span class="special">,</span> <span class="keyword">int</span><span class="special">,</span> <span class="keyword">unsigned</span><span class="special">&gt;</span> <span class="identifier">v1</span><span class="special">(</span> <span class="number">1</span> <span class="special">);</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">"("</span> <span class="special">&lt;&lt;</span> <span class="identifier">name</span><span class="special">&lt;</span><span class="keyword">decltype</span><span class="special">(</span><span class="identifier">v1</span><span class="special">)&gt;()</span> <span class="special">&lt;&lt;</span> <span class="string">")v1: "</span><span class="special">;</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">visit</span><span class="special">(</span> <span class="special">[](</span> <span class="keyword">auto</span> <span class="keyword">const</span><span class="special">&amp;</span> <span class="identifier">x</span> <span class="special">){</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">"("</span> <span class="special">&lt;&lt;</span> <span class="identifier">name</span><span class="special">&lt;</span><span class="keyword">decltype</span><span class="special">(</span><span class="identifier">x</span><span class="special">)&gt;()</span> <span class="special">&lt;&lt;</span> <span class="string">")"</span> <span class="special">&lt;&lt;</span> <span class="identifier">x</span> <span class="special">&lt;&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span> <span class="special">},</span> <span class="identifier">v1</span> <span class="special">);</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">variant</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">,</span> <span class="keyword">float</span><span class="special">,</span> <span class="keyword">double</span><span class="special">&gt;</span> <span class="identifier">v2</span><span class="special">(</span> <span class="number">2.0f</span> <span class="special">);</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">"("</span> <span class="special">&lt;&lt;</span> <span class="identifier">name</span><span class="special">&lt;</span><span class="keyword">decltype</span><span class="special">(</span><span class="identifier">v2</span><span class="special">)&gt;()</span> <span class="special">&lt;&lt;</span> <span class="string">")v2: "</span><span class="special">;</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">visit</span><span class="special">(</span> <span class="special">[](</span> <span class="keyword">auto</span> <span class="keyword">const</span><span class="special">&amp;</span> <span class="identifier">x</span> <span class="special">){</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">"("</span> <span class="special">&lt;&lt;</span> <span class="identifier">name</span><span class="special">&lt;</span><span class="keyword">decltype</span><span class="special">(</span><span class="identifier">x</span><span class="special">)&gt;()</span> <span class="special">&lt;&lt;</span> <span class="string">")"</span> <span class="special">&lt;&lt;</span> <span class="identifier">x</span> <span class="special">&lt;&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span> <span class="special">},</span> <span class="identifier">v2</span> <span class="special">);</span>
<span class="keyword">auto</span> <span class="identifier">v3</span> <span class="special">=</span> <span class="identifier">rvisit</span><span class="special">(</span> <span class="special">[](</span> <span class="keyword">auto</span> <span class="keyword">const</span><span class="special">&amp;</span> <span class="identifier">x</span><span class="special">,</span> <span class="keyword">auto</span> <span class="keyword">const</span><span class="special">&amp;</span> <span class="identifier">y</span> <span class="special">){</span> <span class="keyword">return</span> <span class="identifier">x</span> <span class="special">+</span> <span class="identifier">y</span><span class="special">;</span> <span class="special">},</span> <span class="identifier">v1</span><span class="special">,</span> <span class="identifier">v2</span> <span class="special">);</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">"("</span> <span class="special">&lt;&lt;</span> <span class="identifier">name</span><span class="special">&lt;</span><span class="keyword">decltype</span><span class="special">(</span><span class="identifier">v3</span><span class="special">)&gt;()</span> <span class="special">&lt;&lt;</span> <span class="string">")v3: "</span><span class="special">;</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">visit</span><span class="special">(</span> <span class="special">[](</span> <span class="keyword">auto</span> <span class="keyword">const</span><span class="special">&amp;</span> <span class="identifier">x</span> <span class="special">){</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">"("</span> <span class="special">&lt;&lt;</span> <span class="identifier">name</span><span class="special">&lt;</span><span class="keyword">decltype</span><span class="special">(</span><span class="identifier">x</span><span class="special">)&gt;()</span> <span class="special">&lt;&lt;</span> <span class="string">")"</span> <span class="special">&lt;&lt;</span> <span class="identifier">x</span> <span class="special">&lt;&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span> <span class="special">},</span> <span class="identifier">v3</span> <span class="special">);</span>
<span class="special">}</span>
</pre>
</div>
</div>
<div class="section">
<div class="titlepage"><div><div><h2 class="title" style="clear: both">
<a name="mp11.reference"></a><a class="link" href="mp11.html#mp11.reference" title="Reference">Reference</a>
</h2></div></div></div>
<p>
The contents of the library are in namespace <code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">mp11</span></code>, unless
specified otherwise.
</p>
<div class="section">
<div class="titlepage"><div><div><h3 class="title"> <div class="titlepage"><div><div><h3 class="title">
<a name="mp11.reference.integral"></a><a class="link" href="mp11.html#mp11.reference.integral" title="Integral Constants, &lt;boost/mp11/integral.hpp&gt;">Integral Constants, <code class="computeroutput"><span class="special">&lt;</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">mp11</span><span class="special">/</span><span class="identifier">integral</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span></code></a> <a name="mp11.reference.integral"></a><a class="link" href="mp11.html#mp11.reference.integral" title="Integral Constants, &lt;boost/mp11/integral.hpp&gt;">Integral Constants, <code class="computeroutput"><span class="special">&lt;</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">mp11</span><span class="special">/</span><span class="identifier">integral</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span></code></a>
</h3></div></div></div> </h3></div></div></div>
@@ -1373,7 +1604,7 @@
</div> </div>
</div> </div>
<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr> <table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
<td align="left"><p><small>Last revised: March 17, 2017 at 00:17:37 GMT</small></p></td> <td align="left"><p><small>Last revised: March 17, 2017 at 03:26:57 GMT</small></p></td>
<td align="right"><div class="copyright-footer"></div></td> <td align="right"><div class="copyright-footer"></div></td>
</tr></table> </tr></table>
<hr> <hr>

View File

@@ -23,17 +23,14 @@
[template endsimplesect[] [template endsimplesect[]
[block '''</simplesect>''']] [block '''</simplesect>''']]
[section Overview]
[include mp11/overview.qbk] [include mp11/overview.qbk]
[include mp11/definitions.qbk]
[endsect] [include mp11/examples.qbk]
[section Reference] [section Reference]
The contents of the library are in namespace `boost::mp11`, unless specified otherwise. The contents of the library are in namespace `boost::mp11`, unless specified otherwise.
[include mp11/definitions.qbk]
[include mp11/integral.qbk] [include mp11/integral.qbk]
[include mp11/list.qbk] [include mp11/list.qbk]
[include mp11/utility.qbk] [include mp11/utility.qbk]

175
doc/mp11/examples.qbk Normal file
View File

@@ -0,0 +1,175 @@
[/
/ Copyright 2017 Peter Dimov
/
/ Distributed under the Boost Software License, Version 1.0. (See
/ accompanying file LICENSE_1_0.txt or copy at
/ http://www.boost.org/LICENSE_1_0.txt)
/]
[section Examples]
[section Generating Test Cases]
Let's suppose that we have written a metafunction `result<T, U>`:
template<class T> using promote = std::common_type_t<T, int>;
template<class T, class U> using result = std::common_type_t<promote<T>, promote<U>>;
that ought to represent the result of an arithmetic operation on the integer types `T` and `U`,
for example `t + u`. We want to test whether `result<T, U>` gives correct results for various combinations
of `T` and `U`, so we write the function
template<class T1, class T2> void test_result()
{
using T3 = decltype( T1() + T2() );
using T4 = result<T1, T2>;
std::cout << ( std::is_same<T3, T4>::value? "[PASS]": "[FAIL]" ) << std::endl;
}
and then need to call it a substantial number of times:
int main()
{
test_result<char, char>();
test_result<char, short>();
test_result<char, int>();
test_result<char, unsigned>();
// ...
}
Writing all those type combinations by hand is unwieldy, error prone, and worst of all, boring. This is
how we can leverage Mp11 to automate the task:
#include <boost/mp11.hpp>
#include <boost/tuple_for_each.hpp>
#include <boost/core/demangle.hpp>
#include <type_traits>
#include <iostream>
#include <typeinfo>
using namespace boost::mp11;
template<class T> std::string name()
{
return boost::core::demangle( typeid(T).name() );
}
template<class T> using promote = std::common_type_t<T, int>;
template<class T, class U> using result = std::common_type_t<promote<T>, promote<U>>;
template<class T1, class T2> void test_result( mp_list<T1, T2> const& )
{
using T3 = decltype( T1() + T2() );
using T4 = result<T1, T2>;
std::cout << ( std::is_same<T3, T4>::value? "[PASS] ": "[FAIL] " ) << name<T1>() << " + " << name<T2>() << " -> " << name<T3>() << ", result: " << name<T4>() << " " << std::endl;
}
int main()
{
using L = std::tuple<char, short, int, unsigned, long, unsigned long>;
boost::tuple_for_each( mp_product<mp_list, L, L>(), [](auto&& x){ test_result(x); } );
}
[endsect]
[section Computing Return Types]
C++17 has a standard variant type, called `std::variant`. It also defines a function template
`std::visit` that can be used to apply a function to the contained value of one or more `variant`s.
So for instance, if the `variant` `v1` contains `1`, and the `variant` `v2` contains `2.0f`,
`std::visit(f, v1, v2)` will call `f(1, 2.0f)`.
However, `std::visit` has one limitation: it cannot return a result unless all
possible applications of the function have the same return type. If, for instance, `v1` and `v2`
are both of type `std::variant<short, int, float>`,
std::visit( []( auto const& x, auto const& y ){ return x + y; }, v1, v2 );
will fail to compile because the result of `x + y` can be either `int` or `float` depending on
what `v1` and `v2` hold.
A type that can hold either `int` or `float` already exists, called, surprisingly enough, `std::variant<int, float>`.
Let's write our own function template `rvisit` that is the same as `visit` but returns a `variant`:
template<class F, class... V> auto rvisit( F&& f, V&&... v )
{
using R = /*...*/;
return std::visit( [&]( auto&&... x ){ return R( std::forward<F>(f)( std::forward<decltype(x)>(x)... ) ); }, std::forward<V>( v )... );
}
What this does is basically calls `std::visit` to do the work, but instead of passing it `f`, we pass a lambda that does the same as `f` except
it converts the result to a common type `R`. `R` is supposed to be `std::variant<...>` where the ellipsis denotes the return types of
calling `f` with all possible combinations of variant values.
We'll first define a helper quoted metafunction `Qret<F>` that returns the result of the application of `F` to arguments of type `T...`:
template<class F> struct Qret
{
template<class... T> using invoke = decltype( std::declval<F>()( std::declval<T>()... ) );
};
(Unfortunately, we can't just define this metafunction inside `rvisit`; the language prohibits defining template aliases inside functions.)
With `Qret` in hand, a `variant` of the possible return types is just a matter of applying it over the possible combinations of the variant values:
using R = mp_product<Qret<F>::template invoke, std::remove_reference_t<V>...>;
Why does this work? `mp_product<F, L1<T1...>, L2<T2...>, ..., Ln<Tn...>>` returns `L1<F<U1, U2, ..., Un>, ...>`, where `Ui` traverse all
possible combinations of list values. Since in our case all `Li` are `std::variant`, the result will also be `std::variant`.
One more step remains. Suppose that, as above, we're passing two variants of type `std::variant<short, int, float>` and `F` is
`[]( auto const& x, auto const& y ){ return x + y; }`. This will generate `R` of length 9, one per each combination, but many of those
elements will be the same, either `int` or `float`, and we need to filter out the duplicates. So,
using R = mp_unique<mp_product<Qret<F>::template invoke, std::remove_reference_t<V>...>>;
and we're done:
#include <boost/mp11.hpp>
#include <boost/core/demangle.hpp>
#include <variant>
#include <type_traits>
#include <typeinfo>
#include <iostream>
using namespace boost::mp11;
template<class F> struct Qret
{
template<class... T> using invoke = decltype( std::declval<F>()( std::declval<T>()... ) );
};
template<class F, class... V> auto rvisit( F&& f, V&&... v )
{
using R = mp_unique<mp_product<Qret<F>::template invoke, std::remove_reference_t<V>...>>;
return std::visit( [&]( auto&&... x ){ return R( std::forward<F>(f)( std::forward<decltype(x)>(x)... ) ); }, std::forward<V>( v )... );
}
template<class T> std::string name()
{
return boost::core::demangle( typeid(T).name() );
}
int main()
{
std::variant<signed char, unsigned char, signed short, unsigned short, int, unsigned> v1( 1 );
std::cout << "(" << name<decltype(v1)>() << ")v1: ";
std::visit( []( auto const& x ){ std::cout << "(" << name<decltype(x)>() << ")" << x << std::endl; }, v1 );
std::variant<int, float, double> v2( 2.0f );
std::cout << "(" << name<decltype(v2)>() << ")v2: ";
std::visit( []( auto const& x ){ std::cout << "(" << name<decltype(x)>() << ")" << x << std::endl; }, v2 );
auto v3 = rvisit( []( auto const& x, auto const& y ){ return x + y; }, v1, v2 );
std::cout << "(" << name<decltype(v3)>() << ")v3: ";
std::visit( []( auto const& x ){ std::cout << "(" << name<decltype(x)>() << ")" << x << std::endl; }, v3 );
}
[endsect]
[endsect]

View File

@@ -6,6 +6,8 @@
/ http://www.boost.org/LICENSE_1_0.txt) / http://www.boost.org/LICENSE_1_0.txt)
/] /]
[section Overview]
Mp11 is a C++11 metaprogramming library based on template aliases and variadic templates. Mp11 is a C++11 metaprogramming library based on template aliases and variadic templates.
It implements the approach outlined in the article It implements the approach outlined in the article
[@http://pdimov.com/cpp2/simple_cxx11_metaprogramming.html Simple C++11 metaprogramming] [@http://pdimov.com/cpp2/simple_cxx11_metaprogramming.html Simple C++11 metaprogramming]
@@ -15,15 +17,17 @@ The general principles upon which Mp11 is built are that algorithms and metafunc
template aliases of the form `F<T...>` and data structures are lists of the form `L<T...>`, template aliases of the form `F<T...>` and data structures are lists of the form `L<T...>`,
with the library placing no requirements on `L`. `mp_list<T...>` is the built-in list type, with the library placing no requirements on `L`. `mp_list<T...>` is the built-in list type,
but `std::tuple<T...>`, `std::pair<T1, T2>` and `std::variant<T...>` are also perfectly but `std::tuple<T...>`, `std::pair<T1, T2>` and `std::variant<T...>` are also perfectly
legitimate list types, although of course `std:pair<T1, T2>`, due to having exactly two elements, legitimate list types, although of course `std::pair<T1, T2>`, due to having exactly two elements,
is not resizeable and will consequently not work with algorithms that need to add or remove is not resizeable and will consequently not work with algorithms that need to add or remove
elements. elements.
Another distinguishing feature of this approach is that lists (`L<T...>`) have the same form as Another distinguishing feature of this approach is that lists (`L<T...>`) have the same form as
metafunctions (`F<T...>`) and can therefore be used as such. For example, applying `std::add_pointer_t` metafunctions (`F<T...>`) and can therefore be used as such. For example, applying `std::add_pointer_t`
to the list `std::tuple<int, float>` by way of `mp_transform<std::tuple<int, float>, std::add_pointer_t>` to the list `std::tuple<int, float>` by way of `mp_transform<std::add_pointer_t, std::tuple<int, float>>`
gives us `std::tuple<int*, float*>`, but we can also apply `mp_list` to the same tuple: gives us `std::tuple<int*, float*>`, but we can also apply `mp_list` to the same tuple:
using R = mp_transform<std::tuple<int, float>, mp_list>; using R = mp_transform<mp_list, std::tuple<int, float>>;
and get `std::tuple<mp_list<int>, mp_list<float>>`. and get `std::tuple<mp_list<int>, mp_list<float>>`.
[endsect]