forked from boostorg/mp11
Add examples to documentation.
This commit is contained in:
@@ -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"><</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">></span></code></a></span></dt>
|
<dt><span class="section"><a href="mp11.html#mp11.reference.integral">Integral Constants, <code class="computeroutput"><span class="special"><</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">></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"><</span><span class="identifier">B</span><span class="special">></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"><</span><span class="identifier">B</span><span class="special">></span></code></a></span></dt>
|
||||||
@@ -175,7 +182,7 @@
|
|||||||
<code class="computeroutput"><span class="identifier">mp_list</span><span class="special"><</span><span class="identifier">T</span><span class="special">...></span></code>
|
<code class="computeroutput"><span class="identifier">mp_list</span><span class="special"><</span><span class="identifier">T</span><span class="special">...></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"><</span><span class="identifier">T</span><span class="special">...></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"><</span><span class="identifier">T</span><span class="special">...></span></code>,
|
||||||
<code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">pair</span><span class="special"><</span><span class="identifier">T1</span><span class="special">,</span> <span class="identifier">T2</span><span class="special">></span></code> and <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">variant</span><span class="special"><</span><span class="identifier">T</span><span class="special">...></span></code>
|
<code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">pair</span><span class="special"><</span><span class="identifier">T1</span><span class="special">,</span> <span class="identifier">T2</span><span class="special">></span></code> and <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">variant</span><span class="special"><</span><span class="identifier">T</span><span class="special">...></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"><</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"><</span><span class="identifier">T1</span><span class="special">,</span>
|
||||||
<span class="identifier">T2</span><span class="special">></span></code>,
|
<span class="identifier">T2</span><span class="special">></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"><</span><span class="identifier">T</span><span class="special">...></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"><</span><span class="identifier">T</span><span class="special">...></span></code>) have the same form as metafunctions
|
||||||
(<code class="computeroutput"><span class="identifier">F</span><span class="special"><</span><span class="identifier">T</span><span class="special">...></span></code>)
|
(<code class="computeroutput"><span class="identifier">F</span><span class="special"><</span><span class="identifier">T</span><span class="special">...></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"><</span><span class="keyword">int</span><span class="special">,</span> <span class="keyword">float</span><span class="special">></span></code> by way of <code class="computeroutput"><span class="identifier">mp_transform</span><span class="special"><</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">tuple</span><span class="special"><</span><span class="keyword">int</span><span class="special">,</span> <span class="keyword">float</span><span class="special">>,</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">add_pointer_t</span><span class="special">></span></code> gives us <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">tuple</span><span class="special"><</span><span class="keyword">int</span><span class="special">*,</span> <span class="keyword">float</span><span class="special">*></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"><</span><span class="keyword">int</span><span class="special">,</span> <span class="keyword">float</span><span class="special">></span></code> by way of <code class="computeroutput"><span class="identifier">mp_transform</span><span class="special"><</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"><</span><span class="keyword">int</span><span class="special">,</span> <span class="keyword">float</span><span class="special">>></span></code> gives us <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">tuple</span><span class="special"><</span><span class="keyword">int</span><span class="special">*,</span> <span class="keyword">float</span><span class="special">*></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"><</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">tuple</span><span class="special"><</span><span class="keyword">int</span><span class="special">,</span> <span class="keyword">float</span><span class="special">>,</span> <span class="identifier">mp_list</span><span class="special">>;</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"><</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"><</span><span class="keyword">int</span><span class="special">,</span> <span class="keyword">float</span><span class="special">>>;</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"><</span><span class="identifier">mp_list</span><span class="special"><</span><span class="keyword">int</span><span class="special">>,</span> <span class="identifier">mp_list</span><span class="special"><</span><span class="keyword">float</span><span class="special">>></span></code>.
|
and get <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">tuple</span><span class="special"><</span><span class="identifier">mp_list</span><span class="special"><</span><span class="keyword">int</span><span class="special">>,</span> <span class="identifier">mp_list</span><span class="special"><</span><span class="keyword">float</span><span class="special">>></span></code>.
|
||||||
@@ -195,6 +203,271 @@
|
|||||||
</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.definitions"></a><a class="link" href="mp11.html#mp11.definitions" title="Definitions">Definitions</a>
|
||||||
|
</h2></div></div></div>
|
||||||
|
<p>
|
||||||
|
A <span class="emphasis"><em>list</em></span> is a — possibly but not necessarily variadic — template
|
||||||
|
class whose parameters are all types, for example <code class="computeroutput"><span class="identifier">mp_list</span><span class="special"><</span><span class="keyword">char</span><span class="special">[],</span>
|
||||||
|
<span class="keyword">void</span><span class="special">></span></code>,
|
||||||
|
<code class="computeroutput"><span class="identifier">mp_list</span><span class="special"><></span></code>,
|
||||||
|
<code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">tuple</span><span class="special"><</span><span class="keyword">int</span><span class="special">,</span> <span class="keyword">float</span><span class="special">,</span> <span class="keyword">char</span><span class="special">></span></code>,
|
||||||
|
<code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">pair</span><span class="special"><</span><span class="keyword">int</span><span class="special">,</span> <span class="keyword">float</span><span class="special">></span></code>, <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">shared_ptr</span><span class="special"><</span><span class="identifier">X</span><span class="special">></span></code>.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
A <span class="emphasis"><em>metafunction</em></span> is a class template or a template alias
|
||||||
|
whose parameters are all types, for example <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">add_pointer_t</span></code>,
|
||||||
|
<code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">is_const</span></code>, <code class="computeroutput"><span class="identifier">mp_second</span></code>,
|
||||||
|
<code class="computeroutput"><span class="identifier">mp_push_front</span></code>, <code class="computeroutput"><span class="identifier">mp_list</span></code>, <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">tuple</span></code>,
|
||||||
|
<code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">pair</span></code>, <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">shared_ptr</span></code>,
|
||||||
|
or
|
||||||
|
</p>
|
||||||
|
<pre class="programlisting"><span class="keyword">template</span><span class="special"><</span><span class="keyword">class</span><span class="special">...></span> <span class="keyword">using</span> <span class="identifier">F1</span> <span class="special">=</span> <span class="keyword">void</span><span class="special">;</span>
|
||||||
|
<span class="keyword">template</span><span class="special"><</span><span class="keyword">class</span> <span class="identifier">T</span><span class="special">></span> <span class="keyword">using</span> <span class="identifier">F2</span> <span class="special">=</span> <span class="identifier">T</span><span class="special">*;</span>
|
||||||
|
<span class="keyword">template</span><span class="special"><</span><span class="keyword">class</span><span class="special">...</span> <span class="identifier">T</span><span class="special">></span> <span class="keyword">using</span> <span class="identifier">F3</span> <span class="special">=</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">integral_constant</span><span class="special"><</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span><span class="special">,</span> <span class="keyword">sizeof</span><span class="special">...(</span><span class="identifier">T</span><span class="special">)>;</span>
|
||||||
|
</pre>
|
||||||
|
<p>
|
||||||
|
A <span class="emphasis"><em>quoted metafunction</em></span> is a class with a public metafunction
|
||||||
|
called <code class="computeroutput"><span class="identifier">invoke</span></code>, for example
|
||||||
|
</p>
|
||||||
|
<pre class="programlisting"><span class="keyword">struct</span> <span class="identifier">Q1</span> <span class="special">{</span> <span class="keyword">template</span><span class="special"><</span><span class="keyword">class</span><span class="special">...></span> <span class="keyword">using</span> <span class="identifier">invoke</span> <span class="special">=</span> <span class="keyword">void</span><span class="special">;</span> <span class="special">};</span>
|
||||||
|
<span class="keyword">struct</span> <span class="identifier">Q2</span> <span class="special">{</span> <span class="keyword">template</span><span class="special"><</span><span class="keyword">class</span> <span class="identifier">T</span><span class="special">></span> <span class="keyword">using</span> <span class="identifier">invoke</span> <span class="special">=</span> <span class="identifier">T</span><span class="special">*;</span> <span class="special">};</span>
|
||||||
|
<span class="keyword">struct</span> <span class="identifier">Q3</span> <span class="special">{</span> <span class="keyword">template</span><span class="special"><</span><span class="keyword">class</span><span class="special">...</span> <span class="identifier">T</span><span class="special">></span> <span class="keyword">using</span> <span class="identifier">invoke</span> <span class="special">=</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">integral_constant</span><span class="special"><</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span><span class="special">,</span> <span class="keyword">sizeof</span><span class="special">...(</span><span class="identifier">T</span><span class="special">)>;</span> <span class="special">};</span>
|
||||||
|
</pre>
|
||||||
|
<p>
|
||||||
|
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 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"><</span><span class="keyword">int</span><span class="special">,</span>
|
||||||
|
<span class="number">7</span><span class="special">></span></code>,
|
||||||
|
or
|
||||||
|
</p>
|
||||||
|
<pre class="programlisting"><span class="keyword">struct</span> <span class="identifier">N</span> <span class="special">{</span> <span class="keyword">static</span> <span class="keyword">int</span> <span class="keyword">constexpr</span> <span class="identifier">value</span> <span class="special">=</span> <span class="number">2</span><span class="special">;</span> <span class="special">};</span>
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
<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"><</span><span class="identifier">T</span><span class="special">,</span>
|
||||||
|
<span class="identifier">U</span><span class="special">></span></code>:
|
||||||
|
</p>
|
||||||
|
<pre class="programlisting"><span class="keyword">template</span><span class="special"><</span><span class="keyword">class</span> <span class="identifier">T</span><span class="special">></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"><</span><span class="identifier">T</span><span class="special">,</span> <span class="keyword">int</span><span class="special">>;</span>
|
||||||
|
<span class="keyword">template</span><span class="special"><</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">></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"><</span><span class="identifier">promote</span><span class="special"><</span><span class="identifier">T</span><span class="special">>,</span> <span class="identifier">promote</span><span class="special"><</span><span class="identifier">U</span><span class="special">>>;</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"><</span><span class="identifier">T</span><span class="special">,</span>
|
||||||
|
<span class="identifier">U</span><span class="special">></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"><</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">></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"><</span><span class="identifier">T1</span><span class="special">,</span> <span class="identifier">T2</span><span class="special">>;</span>
|
||||||
|
|
||||||
|
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="special">(</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">is_same</span><span class="special"><</span><span class="identifier">T3</span><span class="special">,</span> <span class="identifier">T4</span><span class="special">>::</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"><<</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"><</span><span class="keyword">char</span><span class="special">,</span> <span class="keyword">char</span><span class="special">>();</span>
|
||||||
|
<span class="identifier">test_result</span><span class="special"><</span><span class="keyword">char</span><span class="special">,</span> <span class="keyword">short</span><span class="special">>();</span>
|
||||||
|
<span class="identifier">test_result</span><span class="special"><</span><span class="keyword">char</span><span class="special">,</span> <span class="keyword">int</span><span class="special">>();</span>
|
||||||
|
<span class="identifier">test_result</span><span class="special"><</span><span class="keyword">char</span><span class="special">,</span> <span class="keyword">unsigned</span><span class="special">>();</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"><</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">></span>
|
||||||
|
<span class="preprocessor">#include</span> <span class="special"><</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">></span>
|
||||||
|
<span class="preprocessor">#include</span> <span class="special"><</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">></span>
|
||||||
|
<span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">type_traits</span><span class="special">></span>
|
||||||
|
<span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">iostream</span><span class="special">></span>
|
||||||
|
<span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">typeinfo</span><span class="special">></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"><</span><span class="keyword">class</span> <span class="identifier">T</span><span class="special">></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"><</span><span class="keyword">class</span> <span class="identifier">T</span><span class="special">></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"><</span><span class="identifier">T</span><span class="special">,</span> <span class="keyword">int</span><span class="special">>;</span>
|
||||||
|
<span class="keyword">template</span><span class="special"><</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">></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"><</span><span class="identifier">promote</span><span class="special"><</span><span class="identifier">T</span><span class="special">>,</span> <span class="identifier">promote</span><span class="special"><</span><span class="identifier">U</span><span class="special">>>;</span>
|
||||||
|
|
||||||
|
<span class="keyword">template</span><span class="special"><</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">></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"><</span><span class="identifier">T1</span><span class="special">,</span> <span class="identifier">T2</span><span class="special">></span> <span class="keyword">const</span><span class="special">&</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"><</span><span class="identifier">T1</span><span class="special">,</span> <span class="identifier">T2</span><span class="special">>;</span>
|
||||||
|
|
||||||
|
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="special">(</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">is_same</span><span class="special"><</span><span class="identifier">T3</span><span class="special">,</span> <span class="identifier">T4</span><span class="special">>::</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"><<</span> <span class="identifier">name</span><span class="special"><</span><span class="identifier">T1</span><span class="special">>()</span> <span class="special"><<</span> <span class="string">" + "</span> <span class="special"><<</span> <span class="identifier">name</span><span class="special"><</span><span class="identifier">T2</span><span class="special">>()</span> <span class="special"><<</span> <span class="string">" -> "</span> <span class="special"><<</span> <span class="identifier">name</span><span class="special"><</span><span class="identifier">T3</span><span class="special">>()</span> <span class="special"><<</span> <span class="string">", result: "</span> <span class="special"><<</span> <span class="identifier">name</span><span class="special"><</span><span class="identifier">T4</span><span class="special">>()</span> <span class="special"><<</span> <span class="string">" "</span> <span class="special"><<</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"><</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">>;</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"><</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">>(),</span> <span class="special">[](</span><span class="keyword">auto</span><span class="special">&&</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"><</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">></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">&</span> <span class="identifier">x</span><span class="special">,</span> <span class="keyword">auto</span> <span class="keyword">const</span><span class="special">&</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"><</span><span class="keyword">int</span><span class="special">,</span>
|
||||||
|
<span class="keyword">float</span><span class="special">></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"><</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">></span> <span class="keyword">auto</span> <span class="identifier">rvisit</span><span class="special">(</span> <span class="identifier">F</span><span class="special">&&</span> <span class="identifier">f</span><span class="special">,</span> <span class="identifier">V</span><span class="special">&&...</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">[&](</span> <span class="keyword">auto</span><span class="special">&&...</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"><</span><span class="identifier">F</span><span class="special">>(</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"><</span><span class="keyword">decltype</span><span class="special">(</span><span class="identifier">x</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> <span class="identifier">std</span><span class="special">::</span><span class="identifier">forward</span><span class="special"><</span><span class="identifier">V</span><span class="special">>(</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"><...></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"><</span><span class="identifier">F</span><span class="special">></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"><</span><span class="keyword">class</span> <span class="identifier">F</span><span class="special">></span> <span class="keyword">struct</span> <span class="identifier">Qret</span>
|
||||||
|
<span class="special">{</span>
|
||||||
|
<span class="keyword">template</span><span class="special"><</span><span class="keyword">class</span><span class="special">...</span> <span class="identifier">T</span><span class="special">></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"><</span><span class="identifier">F</span><span class="special">>()(</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">declval</span><span class="special"><</span><span class="identifier">T</span><span class="special">>()...</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"><</span><span class="identifier">Qret</span><span class="special"><</span><span class="identifier">F</span><span class="special">>::</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"><</span><span class="identifier">V</span><span class="special">>...>;</span>
|
||||||
|
</pre>
|
||||||
|
<p>
|
||||||
|
Why does this work? <code class="computeroutput"><span class="identifier">mp_product</span><span class="special"><</span><span class="identifier">F</span><span class="special">,</span>
|
||||||
|
<span class="identifier">L1</span><span class="special"><</span><span class="identifier">T1</span><span class="special">...>,</span> <span class="identifier">L2</span><span class="special"><</span><span class="identifier">T2</span><span class="special">...>,</span> <span class="special">...,</span> <span class="identifier">Ln</span><span class="special"><</span><span class="identifier">Tn</span><span class="special">...>></span></code> returns <code class="computeroutput"><span class="identifier">L1</span><span class="special"><</span><span class="identifier">F</span><span class="special"><</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">>,</span> <span class="special">...></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"><</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">></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">&</span> <span class="identifier">x</span><span class="special">,</span> <span class="keyword">auto</span> <span class="keyword">const</span><span class="special">&</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"><</span><span class="identifier">mp_product</span><span class="special"><</span><span class="identifier">Qret</span><span class="special"><</span><span class="identifier">F</span><span class="special">>::</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"><</span><span class="identifier">V</span><span class="special">>...>>;</span>
|
||||||
|
</pre>
|
||||||
|
<p>
|
||||||
|
and we're done:
|
||||||
|
</p>
|
||||||
|
<pre class="programlisting"><span class="preprocessor">#include</span> <span class="special"><</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">></span>
|
||||||
|
<span class="preprocessor">#include</span> <span class="special"><</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">></span>
|
||||||
|
<span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">variant</span><span class="special">></span>
|
||||||
|
<span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">type_traits</span><span class="special">></span>
|
||||||
|
<span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">typeinfo</span><span class="special">></span>
|
||||||
|
<span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">iostream</span><span class="special">></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"><</span><span class="keyword">class</span> <span class="identifier">F</span><span class="special">></span> <span class="keyword">struct</span> <span class="identifier">Qret</span>
|
||||||
|
<span class="special">{</span>
|
||||||
|
<span class="keyword">template</span><span class="special"><</span><span class="keyword">class</span><span class="special">...</span> <span class="identifier">T</span><span class="special">></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"><</span><span class="identifier">F</span><span class="special">>()(</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">declval</span><span class="special"><</span><span class="identifier">T</span><span class="special">>()...</span> <span class="special">)</span> <span class="special">);</span>
|
||||||
|
<span class="special">};</span>
|
||||||
|
|
||||||
|
<span class="keyword">template</span><span class="special"><</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">></span> <span class="keyword">auto</span> <span class="identifier">rvisit</span><span class="special">(</span> <span class="identifier">F</span><span class="special">&&</span> <span class="identifier">f</span><span class="special">,</span> <span class="identifier">V</span><span class="special">&&...</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"><</span><span class="identifier">mp_product</span><span class="special"><</span><span class="identifier">Qret</span><span class="special"><</span><span class="identifier">F</span><span class="special">>::</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"><</span><span class="identifier">V</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">[&](</span> <span class="keyword">auto</span><span class="special">&&...</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"><</span><span class="identifier">F</span><span class="special">>(</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"><</span><span class="keyword">decltype</span><span class="special">(</span><span class="identifier">x</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> <span class="identifier">std</span><span class="special">::</span><span class="identifier">forward</span><span class="special"><</span><span class="identifier">V</span><span class="special">>(</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"><</span><span class="keyword">class</span> <span class="identifier">T</span><span class="special">></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"><</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">></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"><<</span> <span class="string">"("</span> <span class="special"><<</span> <span class="identifier">name</span><span class="special"><</span><span class="keyword">decltype</span><span class="special">(</span><span class="identifier">v1</span><span class="special">)>()</span> <span class="special"><<</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">&</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"><<</span> <span class="string">"("</span> <span class="special"><<</span> <span class="identifier">name</span><span class="special"><</span><span class="keyword">decltype</span><span class="special">(</span><span class="identifier">x</span><span class="special">)>()</span> <span class="special"><<</span> <span class="string">")"</span> <span class="special"><<</span> <span class="identifier">x</span> <span class="special"><<</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"><</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">></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"><<</span> <span class="string">"("</span> <span class="special"><<</span> <span class="identifier">name</span><span class="special"><</span><span class="keyword">decltype</span><span class="special">(</span><span class="identifier">v2</span><span class="special">)>()</span> <span class="special"><<</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">&</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"><<</span> <span class="string">"("</span> <span class="special"><<</span> <span class="identifier">name</span><span class="special"><</span><span class="keyword">decltype</span><span class="special">(</span><span class="identifier">x</span><span class="special">)>()</span> <span class="special"><<</span> <span class="string">")"</span> <span class="special"><<</span> <span class="identifier">x</span> <span class="special"><<</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">&</span> <span class="identifier">x</span><span class="special">,</span> <span class="keyword">auto</span> <span class="keyword">const</span><span class="special">&</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"><<</span> <span class="string">"("</span> <span class="special"><<</span> <span class="identifier">name</span><span class="special"><</span><span class="keyword">decltype</span><span class="special">(</span><span class="identifier">v3</span><span class="special">)>()</span> <span class="special"><<</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">&</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"><<</span> <span class="string">"("</span> <span class="special"><<</span> <span class="identifier">name</span><span class="special"><</span><span class="keyword">decltype</span><span class="special">(</span><span class="identifier">x</span><span class="special">)>()</span> <span class="special"><<</span> <span class="string">")"</span> <span class="special"><<</span> <span class="identifier">x</span> <span class="special"><<</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>
|
<a name="mp11.reference"></a><a class="link" href="mp11.html#mp11.reference" title="Reference">Reference</a>
|
||||||
</h2></div></div></div>
|
</h2></div></div></div>
|
||||||
<p>
|
<p>
|
||||||
@@ -203,48 +476,6 @@
|
|||||||
</p>
|
</p>
|
||||||
<div class="section">
|
<div class="section">
|
||||||
<div class="titlepage"><div><div><h3 class="title">
|
<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>
|
|
||||||
A <span class="emphasis"><em>list</em></span> is a — possibly but not necessarily variadic — template
|
|
||||||
class whose parameters are all types, for example <code class="computeroutput"><span class="identifier">mp_list</span><span class="special"><</span><span class="keyword">char</span><span class="special">[],</span>
|
|
||||||
<span class="keyword">void</span><span class="special">></span></code>,
|
|
||||||
<code class="computeroutput"><span class="identifier">mp_list</span><span class="special"><></span></code>,
|
|
||||||
<code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">tuple</span><span class="special"><</span><span class="keyword">int</span><span class="special">,</span> <span class="keyword">float</span><span class="special">,</span> <span class="keyword">char</span><span class="special">></span></code>,
|
|
||||||
<code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">pair</span><span class="special"><</span><span class="keyword">int</span><span class="special">,</span> <span class="keyword">float</span><span class="special">></span></code>, <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">shared_ptr</span><span class="special"><</span><span class="identifier">X</span><span class="special">></span></code>.
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
A <span class="emphasis"><em>metafunction</em></span> is a class template or a template alias
|
|
||||||
whose parameters are all types, for example <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">add_pointer_t</span></code>,
|
|
||||||
<code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">is_const</span></code>, <code class="computeroutput"><span class="identifier">mp_second</span></code>,
|
|
||||||
<code class="computeroutput"><span class="identifier">mp_push_front</span></code>, <code class="computeroutput"><span class="identifier">mp_list</span></code>, <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">tuple</span></code>,
|
|
||||||
<code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">pair</span></code>, <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">shared_ptr</span></code>,
|
|
||||||
or
|
|
||||||
</p>
|
|
||||||
<pre class="programlisting"><span class="keyword">template</span><span class="special"><</span><span class="keyword">class</span><span class="special">...></span> <span class="keyword">using</span> <span class="identifier">F1</span> <span class="special">=</span> <span class="keyword">void</span><span class="special">;</span>
|
|
||||||
<span class="keyword">template</span><span class="special"><</span><span class="keyword">class</span> <span class="identifier">T</span><span class="special">></span> <span class="keyword">using</span> <span class="identifier">F2</span> <span class="special">=</span> <span class="identifier">T</span><span class="special">*;</span>
|
|
||||||
<span class="keyword">template</span><span class="special"><</span><span class="keyword">class</span><span class="special">...</span> <span class="identifier">T</span><span class="special">></span> <span class="keyword">using</span> <span class="identifier">F3</span> <span class="special">=</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">integral_constant</span><span class="special"><</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span><span class="special">,</span> <span class="keyword">sizeof</span><span class="special">...(</span><span class="identifier">T</span><span class="special">)>;</span>
|
|
||||||
</pre>
|
|
||||||
<p>
|
|
||||||
A <span class="emphasis"><em>quoted metafunction</em></span> is a class with a public metafunction
|
|
||||||
called <code class="computeroutput"><span class="identifier">invoke</span></code>, for example
|
|
||||||
</p>
|
|
||||||
<pre class="programlisting"><span class="keyword">struct</span> <span class="identifier">Q1</span> <span class="special">{</span> <span class="keyword">template</span><span class="special"><</span><span class="keyword">class</span><span class="special">...></span> <span class="keyword">using</span> <span class="identifier">invoke</span> <span class="special">=</span> <span class="keyword">void</span><span class="special">;</span> <span class="special">};</span>
|
|
||||||
<span class="keyword">struct</span> <span class="identifier">Q2</span> <span class="special">{</span> <span class="keyword">template</span><span class="special"><</span><span class="keyword">class</span> <span class="identifier">T</span><span class="special">></span> <span class="keyword">using</span> <span class="identifier">invoke</span> <span class="special">=</span> <span class="identifier">T</span><span class="special">*;</span> <span class="special">};</span>
|
|
||||||
<span class="keyword">struct</span> <span class="identifier">Q3</span> <span class="special">{</span> <span class="keyword">template</span><span class="special"><</span><span class="keyword">class</span><span class="special">...</span> <span class="identifier">T</span><span class="special">></span> <span class="keyword">using</span> <span class="identifier">invoke</span> <span class="special">=</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">integral_constant</span><span class="special"><</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span><span class="special">,</span> <span class="keyword">sizeof</span><span class="special">...(</span><span class="identifier">T</span><span class="special">)>;</span> <span class="special">};</span>
|
|
||||||
</pre>
|
|
||||||
<p>
|
|
||||||
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
|
|
||||||
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"><</span><span class="keyword">int</span><span class="special">,</span>
|
|
||||||
<span class="number">7</span><span class="special">></span></code>,
|
|
||||||
or
|
|
||||||
</p>
|
|
||||||
<pre class="programlisting"><span class="keyword">struct</span> <span class="identifier">N</span> <span class="special">{</span> <span class="keyword">static</span> <span class="keyword">int</span> <span class="keyword">constexpr</span> <span class="identifier">value</span> <span class="special">=</span> <span class="number">2</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.reference.integral"></a><a class="link" href="mp11.html#mp11.reference.integral" title="Integral Constants, <boost/mp11/integral.hpp>">Integral Constants, <code class="computeroutput"><span class="special"><</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">></span></code></a>
|
<a name="mp11.reference.integral"></a><a class="link" href="mp11.html#mp11.reference.integral" title="Integral Constants, <boost/mp11/integral.hpp>">Integral Constants, <code class="computeroutput"><span class="special"><</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">></span></code></a>
|
||||||
</h3></div></div></div>
|
</h3></div></div></div>
|
||||||
<p>
|
<p>
|
||||||
@@ -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>
|
||||||
|
@@ -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
175
doc/mp11/examples.qbk
Normal 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]
|
@@ -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]
|
||||||
|
Reference in New Issue
Block a user