1
0
forked from boostorg/mp11

Add more examples

This commit is contained in:
Peter Dimov
2017-05-17 20:47:25 +03:00
parent 15e45290d0
commit 47ee95b1f2
3 changed files with 624 additions and 1 deletions

View File

@@ -38,6 +38,7 @@
<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.fixing_tuple_cat">Fixing <code class="computeroutput"><span class="identifier">tuple_cat</span></code></a></span></dt>
<dt><span class="section"><a href="mp11.html#mp11.examples.computing_return_types">Computing Return
Types</a></span></dt>
</dl></dd>
@@ -366,6 +367,258 @@
<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>
<p>
How does it work?
</p>
<p>
<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">,</span> <span class="identifier">L2</span><span class="special">&gt;</span></code>
calls <code class="computeroutput"><span class="identifier">F</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> where <code class="computeroutput"><span class="identifier">T1</span></code>
varies over the elements of <code class="computeroutput"><span class="identifier">L1</span></code>
and <code class="computeroutput"><span class="identifier">T2</span></code> varies over the elements
of <code class="computeroutput"><span class="identifier">L2</span></code>, as if by executing
two nested loops. It then returns a list of these results, of the same type
as <code class="computeroutput"><span class="identifier">L1</span></code>.
</p>
<p>
In our case, both lists are the same <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">tuple</span></code>,
and <code class="computeroutput"><span class="identifier">F</span></code> is <code class="computeroutput"><span class="identifier">mp_list</span></code>,
so <code class="computeroutput"><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></code> will get 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="identifier">mp_list</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">mp_list</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">mp_list</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="special">...,</span> <span class="identifier">mp_list</span><span class="special">&lt;</span><span class="keyword">unsigned</span> <span class="keyword">long</span><span class="special">,</span> <span class="keyword">long</span><span class="special">&gt;,</span> <span class="identifier">mp_list</span><span class="special">&lt;</span><span class="keyword">unsigned</span> <span class="keyword">long</span><span class="special">,</span> <span class="keyword">unsigned</span>
<span class="keyword">long</span><span class="special">&gt;&gt;</span></code>.
</p>
<p>
We then default-construct this tuple and pass it to <code class="computeroutput"><span class="identifier">tuple_for_each</span></code>.
<code class="computeroutput"><span class="identifier">tuple_for_each</span><span class="special">(</span><span class="identifier">tp</span><span class="special">,</span> <span class="identifier">f</span><span class="special">)</span></code> calls <code class="computeroutput"><span class="identifier">f</span></code>
for every tuple element; we use a (C++14) lambda that calls <code class="computeroutput"><span class="identifier">test_result</span></code>. (In pure C++11, we'd need
to make <code class="computeroutput"><span class="identifier">test_result</span></code> a function
object with a templated <code class="computeroutput"><span class="keyword">operator</span><span class="special">()</span></code> and pass that to <code class="computeroutput"><span class="identifier">tuple_for_each</span></code>
directly.)
</p>
</div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="mp11.examples.fixing_tuple_cat"></a><a class="link" href="mp11.html#mp11.examples.fixing_tuple_cat" title="Fixing tuple_cat">Fixing <code class="computeroutput"><span class="identifier">tuple_cat</span></code></a>
</h3></div></div></div>
<p>
The article <a href="http://pdimov.com/cpp2/simple_cxx11_metaprogramming.html" target="_top">Simple
C++11 metaprogramming</a> builds an implementation of the standard function
<code class="computeroutput"><span class="identifier">tuple_cat</span></code>, with the end result
given below:
</p>
<pre class="programlisting"><span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">class</span> <span class="identifier">L</span><span class="special">&gt;</span> <span class="keyword">using</span> <span class="identifier">F</span> <span class="special">=</span> <span class="identifier">mp_iota</span><span class="special">&lt;</span><span class="identifier">mp_size</span><span class="special">&lt;</span><span class="identifier">L</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">R</span><span class="special">,</span> <span class="keyword">class</span><span class="special">...</span><span class="identifier">Is</span><span class="special">,</span> <span class="keyword">class</span><span class="special">...</span> <span class="identifier">Ks</span><span class="special">,</span> <span class="keyword">class</span> <span class="identifier">Tp</span><span class="special">&gt;</span>
<span class="identifier">R</span> <span class="identifier">tuple_cat_</span><span class="special">(</span> <span class="identifier">mp_list</span><span class="special">&lt;</span><span class="identifier">Is</span><span class="special">...&gt;,</span> <span class="identifier">mp_list</span><span class="special">&lt;</span><span class="identifier">Ks</span><span class="special">...&gt;,</span> <span class="identifier">Tp</span> <span class="identifier">tp</span> <span class="special">)</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">get</span><span class="special">&lt;</span><span class="identifier">Ks</span><span class="special">::</span><span class="identifier">value</span><span class="special">&gt;(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">get</span><span class="special">&lt;</span><span class="identifier">Is</span><span class="special">::</span><span class="identifier">value</span><span class="special">&gt;(</span><span class="identifier">tp</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="special">...</span> <span class="identifier">Tp</span><span class="special">,</span>
<span class="keyword">class</span> <span class="identifier">R</span> <span class="special">=</span> <span class="identifier">mp_append</span><span class="special">&lt;</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">tuple</span><span class="special">&lt;&gt;,</span> <span class="keyword">typename</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">remove_reference</span><span class="special">&lt;</span><span class="identifier">Tp</span><span class="special">&gt;::</span><span class="identifier">type</span><span class="special">...&gt;&gt;</span>
<span class="identifier">R</span> <span class="identifier">tuple_cat</span><span class="special">(</span> <span class="identifier">Tp</span> <span class="special">&amp;&amp;...</span> <span class="identifier">tp</span> <span class="special">)</span>
<span class="special">{</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span> <span class="keyword">const</span> <span class="identifier">N</span> <span class="special">=</span> <span class="keyword">sizeof</span><span class="special">...(</span><span class="identifier">Tp</span><span class="special">);</span>
<span class="comment">// inner</span>
<span class="keyword">using</span> <span class="identifier">list1</span> <span class="special">=</span> <span class="identifier">mp_list</span><span class="special">&lt;</span><span class="identifier">mp_rename</span><span class="special">&lt;</span><span class="keyword">typename</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">remove_reference</span><span class="special">&lt;</span><span class="identifier">Tp</span><span class="special">&gt;::</span><span class="identifier">type</span><span class="special">,</span> <span class="identifier">mp_list</span><span class="special">&gt;...&gt;;</span>
<span class="keyword">using</span> <span class="identifier">list2</span> <span class="special">=</span> <span class="identifier">mp_iota_c</span><span class="special">&lt;</span><span class="identifier">N</span><span class="special">&gt;;</span>
<span class="keyword">using</span> <span class="identifier">list3</span> <span class="special">=</span> <span class="identifier">mp_transform</span><span class="special">&lt;</span><span class="identifier">mp_fill</span><span class="special">,</span> <span class="identifier">list1</span><span class="special">,</span> <span class="identifier">list2</span><span class="special">&gt;;</span>
<span class="keyword">using</span> <span class="identifier">inner</span> <span class="special">=</span> <span class="identifier">mp_apply</span><span class="special">&lt;</span><span class="identifier">mp_append</span><span class="special">,</span> <span class="identifier">list3</span><span class="special">&gt;;</span>
<span class="comment">// outer</span>
<span class="keyword">using</span> <span class="identifier">list4</span> <span class="special">=</span> <span class="identifier">mp_transform</span><span class="special">&lt;</span><span class="identifier">F</span><span class="special">,</span> <span class="identifier">list1</span><span class="special">&gt;;</span>
<span class="keyword">using</span> <span class="identifier">outer</span> <span class="special">=</span> <span class="identifier">mp_apply</span><span class="special">&lt;</span><span class="identifier">mp_append</span><span class="special">,</span> <span class="identifier">list4</span><span class="special">&gt;;</span>
<span class="comment">//</span>
<span class="keyword">return</span> <span class="identifier">tuple_cat_</span><span class="special">&lt;</span><span class="identifier">R</span><span class="special">&gt;(</span> <span class="identifier">inner</span><span class="special">(),</span> <span class="identifier">outer</span><span class="special">(),</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">forward_as_tuple</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">Tp</span><span class="special">&gt;(</span><span class="identifier">tp</span><span class="special">)...</span> <span class="special">)</span> <span class="special">);</span>
<span class="special">}</span>
</pre>
<p>
This function, however, is not entirely correct, in that it doesn't handle
some cases properly. For example, trying to concatenate tuples containing
move-only elements such as <code class="computeroutput"><span class="identifier">unique_ptr</span></code>
fails:
</p>
<pre class="programlisting"><span class="identifier">std</span><span class="special">::</span><span class="identifier">tuple</span><span class="special">&lt;</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">unique_ptr</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">&gt;&gt;</span> <span class="identifier">t1</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="identifier">std</span><span class="special">::</span><span class="identifier">unique_ptr</span><span class="special">&lt;</span><span class="keyword">float</span><span class="special">&gt;&gt;</span> <span class="identifier">t2</span><span class="special">;</span>
<span class="keyword">auto</span> <span class="identifier">result</span> <span class="special">=</span> <span class="special">::</span><span class="identifier">tuple_cat</span><span class="special">(</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">move</span><span class="special">(</span> <span class="identifier">t1</span> <span class="special">),</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">move</span><span class="special">(</span> <span class="identifier">t2</span> <span class="special">)</span> <span class="special">);</span>
</pre>
<p>
Trying to concatenate <code class="computeroutput"><span class="keyword">const</span></code>
tuples fails:
</p>
<pre class="programlisting"><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">&gt;</span> <span class="keyword">const</span> <span class="identifier">t1</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">float</span><span class="special">&gt;</span> <span class="keyword">const</span> <span class="identifier">t2</span><span class="special">;</span>
<span class="keyword">auto</span> <span class="identifier">result</span> <span class="special">=</span> <span class="special">::</span><span class="identifier">tuple_cat</span><span class="special">(</span> <span class="identifier">t1</span><span class="special">,</span> <span class="identifier">t2</span> <span class="special">);</span>
</pre>
<p>
And finally, the standard <code class="computeroutput"><span class="identifier">tuple_cat</span></code>
is specified to work on arbitrary tuple-like types (that is, all types that
support <code class="computeroutput"><span class="identifier">tuple_size</span></code>, <code class="computeroutput"><span class="identifier">tuple_element</span></code>, and <code class="computeroutput"><span class="identifier">get</span></code>),
while our implementation only works with <code class="computeroutput"><span class="identifier">tuple</span></code>
and <code class="computeroutput"><span class="identifier">pair</span></code>. <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">array</span></code>,
for example, fails:
</p>
<pre class="programlisting"><span class="identifier">std</span><span class="special">::</span><span class="identifier">array</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">,</span> <span class="number">2</span><span class="special">&gt;</span> <span class="identifier">t1</span><span class="special">{</span> <span class="number">1</span><span class="special">,</span> <span class="number">2</span> <span class="special">};</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">array</span><span class="special">&lt;</span><span class="keyword">float</span><span class="special">,</span> <span class="number">3</span><span class="special">&gt;</span> <span class="identifier">t2</span><span class="special">{</span> <span class="number">3.0f</span><span class="special">,</span> <span class="number">4.0f</span><span class="special">,</span> <span class="number">5.0f</span> <span class="special">};</span>
<span class="keyword">auto</span> <span class="identifier">result</span> <span class="special">=</span> <span class="special">::</span><span class="identifier">tuple_cat</span><span class="special">(</span> <span class="identifier">t1</span><span class="special">,</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">move</span><span class="special">(</span> <span class="identifier">t2</span> <span class="special">)</span> <span class="special">);</span>
</pre>
<p>
Let's fix these one by one. Support for move-only types is easy, if one knows
where to look. The problem is that <code class="computeroutput"><span class="identifier">Tp</span></code>
that we're passing to the helper <code class="computeroutput"><span class="identifier">tuple_cat_</span></code>
is (correctly) <code class="computeroutput"><span class="identifier">tuple</span><span class="special">&lt;</span><span class="identifier">unique_ptr</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">&gt;&amp;&amp;,</span>
<span class="identifier">unique_ptr</span><span class="special">&lt;</span><span class="keyword">float</span><span class="special">&gt;&amp;&amp;&gt;</span></code>,
but <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">get</span><span class="special">&lt;</span><span class="number">0</span><span class="special">&gt;(</span><span class="identifier">tp</span><span class="special">)</span></code> still returns <code class="computeroutput"><span class="identifier">unique_ptr</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">&gt;&amp;</span></code>,
because <code class="computeroutput"><span class="identifier">tp</span></code> is an lvalue.
This behavior is a bit surprising, but consistent with how rvalue reference
members are treated by the language.
</p>
<p>
Long story short, we need <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">move</span><span class="special">(</span><span class="identifier">tp</span><span class="special">)</span></code>
in <code class="computeroutput"><span class="identifier">tuple_cat_</span></code> to make <code class="computeroutput"><span class="identifier">tp</span></code> an rvalue:
</p>
<pre class="programlisting"><span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">class</span> <span class="identifier">R</span><span class="special">,</span> <span class="keyword">class</span><span class="special">...</span><span class="identifier">Is</span><span class="special">,</span> <span class="keyword">class</span><span class="special">...</span> <span class="identifier">Ks</span><span class="special">,</span> <span class="keyword">class</span> <span class="identifier">Tp</span><span class="special">&gt;</span>
<span class="identifier">R</span> <span class="identifier">tuple_cat_</span><span class="special">(</span> <span class="identifier">mp_list</span><span class="special">&lt;</span><span class="identifier">Is</span><span class="special">...&gt;,</span> <span class="identifier">mp_list</span><span class="special">&lt;</span><span class="identifier">Ks</span><span class="special">...&gt;,</span> <span class="identifier">Tp</span> <span class="identifier">tp</span> <span class="special">)</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">get</span><span class="special">&lt;</span><span class="identifier">Ks</span><span class="special">::</span><span class="identifier">value</span><span class="special">&gt;(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">get</span><span class="special">&lt;</span><span class="identifier">Is</span><span class="special">::</span><span class="identifier">value</span><span class="special">&gt;(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">move</span><span class="special">(</span><span class="identifier">tp</span><span class="special">)))...</span> <span class="special">};</span>
<span class="special">}</span>
</pre>
<p>
Next, <code class="computeroutput"><span class="keyword">const</span></code>-qualified tuples.
The issue here is that we're stripping references from the input tuples,
but not <code class="computeroutput"><span class="keyword">const</span></code>. As a result,
we're trying to manipulate types such as <code class="computeroutput"><span class="identifier">tuple</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">&gt;</span>
<span class="keyword">const</span></code> with Mp11 algorithms, and these
types do not fit the list concept. We just need to strip qualifiers as well,
by defining the useful <code class="computeroutput"><span class="identifier">remove_cv_ref</span></code>
primitive that is inexplicably missing from the standard library:
</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">remove_cv_ref</span> <span class="special">=</span> <span class="keyword">typename</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">remove_cv</span><span class="special">&lt;</span>
<span class="keyword">typename</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">remove_reference</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">&gt;::</span><span class="identifier">type</span><span class="special">&gt;::</span><span class="identifier">type</span><span class="special">;</span>
</pre>
<p>
and then by using <code class="computeroutput"><span class="identifier">remove_cv_ref</span><span class="special">&lt;</span><span class="identifier">Tp</span><span class="special">&gt;</span></code> in place of <code class="computeroutput"><span class="keyword">typename</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">remove_reference</span><span class="special">&lt;</span><span class="identifier">Tp</span><span class="special">&gt;::</span><span class="identifier">type</span></code>:
</p>
<pre class="programlisting"><span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">class</span><span class="special">...</span> <span class="identifier">Tp</span><span class="special">,</span>
<span class="keyword">class</span> <span class="identifier">R</span> <span class="special">=</span> <span class="identifier">mp_append</span><span class="special">&lt;</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">tuple</span><span class="special">&lt;&gt;,</span> <span class="identifier">remove_cv_ref</span><span class="special">&lt;</span><span class="identifier">Tp</span><span class="special">&gt;...&gt;&gt;</span>
<span class="identifier">R</span> <span class="identifier">tuple_cat</span><span class="special">(</span> <span class="identifier">Tp</span> <span class="special">&amp;&amp;...</span> <span class="identifier">tp</span> <span class="special">)</span>
<span class="special">{</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span> <span class="keyword">const</span> <span class="identifier">N</span> <span class="special">=</span> <span class="keyword">sizeof</span><span class="special">...(</span><span class="identifier">Tp</span><span class="special">);</span>
<span class="comment">// inner</span>
<span class="keyword">using</span> <span class="identifier">list1</span> <span class="special">=</span> <span class="identifier">mp_list</span><span class="special">&lt;</span><span class="identifier">mp_rename</span><span class="special">&lt;</span><span class="identifier">remove_cv_ref</span><span class="special">&lt;</span><span class="identifier">Tp</span><span class="special">&gt;,</span> <span class="identifier">mp_list</span><span class="special">&gt;...&gt;;</span>
<span class="comment">// ...</span>
</pre>
<p>
Finally, tuple-like types. We've so far exploited the fact that <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">pair</span></code>
and <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">tuple</span></code> are valid Mp11 lists, but in general,
arbitrary tuple-like types aren't, so we need to convert them into such.
For that, we'll need to define a metafunction <code class="computeroutput"><span class="identifier">from_tuple_like</span></code>
that will take an arbitrary tuple-like type and will return, in our case,
the corresponding <code class="computeroutput"><span class="identifier">mp_list</span></code>.
</p>
<p>
Technically, a more principled approach would've been to return <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">tuple</span></code>,
but here <code class="computeroutput"><span class="identifier">mp_list</span></code> will prove
more convenient.
</p>
<p>
What we need is, given a tuple-like type <code class="computeroutput"><span class="identifier">Tp</span></code>,
to obtain <code class="computeroutput"><span class="identifier">mp_list</span><span class="special">&lt;</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">tuple_element</span><span class="special">&lt;</span><span class="number">0</span><span class="special">,</span>
<span class="identifier">Tp</span><span class="special">&gt;,</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">tuple_element</span><span class="special">&lt;</span><span class="number">1</span><span class="special">,</span> <span class="identifier">Tp</span><span class="special">&gt;,</span> <span class="special">...,</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">tuple_element</span><span class="special">&lt;</span><span class="identifier">N</span><span class="special">-</span><span class="number">1</span><span class="special">,</span> <span class="identifier">Tp</span><span class="special">&gt;&gt;</span></code>, where <code class="computeroutput"><span class="identifier">N</span></code>
is <code class="computeroutput"><span class="identifier">tuple_size</span><span class="special">&lt;</span><span class="identifier">Tp</span><span class="special">&gt;::</span><span class="identifier">value</span></code>. Here's one way to do it:
</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">,</span> <span class="keyword">class</span> <span class="identifier">I</span><span class="special">&gt;</span> <span class="keyword">using</span> <span class="identifier">tuple_element</span> <span class="special">=</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">tuple_element_t</span><span class="special">&lt;</span><span class="identifier">I</span><span class="special">::</span><span class="identifier">value</span><span class="special">,</span> <span class="identifier">T</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">&gt;</span> <span class="keyword">using</span> <span class="identifier">from_tuple_like</span> <span class="special">=</span> <span class="identifier">mp_product</span><span class="special">&lt;</span><span class="identifier">tuple_element</span><span class="special">,</span> <span class="identifier">mp_list</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">&gt;,</span> <span class="identifier">mp_iota</span><span class="special">&lt;</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">tuple_size</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">&gt;&gt;&gt;;</span>
</pre>
<p>
(<code class="computeroutput"><span class="identifier">mp_iota</span><span class="special">&lt;</span><span class="identifier">N</span><span class="special">&gt;</span></code> is
an algorithm that returns an <code class="computeroutput"><span class="identifier">mp_list</span></code>
with elements <code class="computeroutput"><span class="identifier">mp_size_t</span><span class="special">&lt;</span><span class="number">0</span><span class="special">&gt;</span></code>, <code class="computeroutput"><span class="identifier">mp_size_t</span><span class="special">&lt;</span><span class="number">1</span><span class="special">&gt;</span></code>, ...,
<code class="computeroutput"><span class="identifier">mp_size_t</span><span class="special">&lt;</span><span class="identifier">N</span><span class="special">-</span><span class="number">1</span><span class="special">&gt;</span></code>.)
</p>
<p>
Remember that <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">,</span> <span class="identifier">L2</span><span class="special">&gt;</span></code>
performs the equivalent of two nested loops over the elements of <code class="computeroutput"><span class="identifier">L1</span></code> and <code class="computeroutput"><span class="identifier">L2</span></code>,
applying <code class="computeroutput"><span class="identifier">F</span></code> to the two variables
and gathering the result. In our case <code class="computeroutput"><span class="identifier">L1</span></code>
consists of the single element <code class="computeroutput"><span class="identifier">T</span></code>,
so only the second loop (over <code class="computeroutput"><span class="identifier">mp_iota</span><span class="special">&lt;</span><span class="identifier">N</span><span class="special">&gt;</span></code>,
where <code class="computeroutput"><span class="identifier">N</span></code> is <code class="computeroutput"><span class="identifier">tuple_size</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">&gt;</span></code>),
remains, and we get a list of the same type as <code class="computeroutput"><span class="identifier">L1</span></code>
(an <code class="computeroutput"><span class="identifier">mp_list</span></code>) with contents
<code class="computeroutput"><span class="identifier">tuple_element</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">,</span> <span class="identifier">mp_size_t</span><span class="special">&lt;</span><span class="number">0</span><span class="special">&gt;&gt;</span></code>,
<code class="computeroutput"><span class="identifier">tuple_element</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">,</span> <span class="identifier">mp_size_t</span><span class="special">&lt;</span><span class="number">1</span><span class="special">&gt;&gt;</span></code>,
..., <code class="computeroutput"><span class="identifier">tuple_element</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">,</span> <span class="identifier">mp_size_t</span><span class="special">&lt;</span><span class="identifier">N</span><span class="special">-</span><span class="number">1</span><span class="special">&gt;&gt;</span></code>.
</p>
<p>
For completeness's sake, here's another, more traditional way to achieve
the same result:
</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">from_tuple_like</span> <span class="special">=</span> <span class="identifier">mp_transform_q</span><span class="special">&lt;</span><span class="identifier">mp_bind_front</span><span class="special">&lt;</span><span class="identifier">tuple_element</span><span class="special">,</span> <span class="identifier">T</span><span class="special">&gt;,</span> <span class="identifier">mp_iota</span><span class="special">&lt;</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">tuple_size</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">&gt;&gt;&gt;;</span>
</pre>
<p>
With all these fixes applied, our fully operational <code class="computeroutput"><span class="identifier">tuple_cat</span></code>
now looks like this:
</p>
<pre class="programlisting"><span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">class</span> <span class="identifier">L</span><span class="special">&gt;</span> <span class="keyword">using</span> <span class="identifier">F</span> <span class="special">=</span> <span class="identifier">mp_iota</span><span class="special">&lt;</span><span class="identifier">mp_size</span><span class="special">&lt;</span><span class="identifier">L</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">R</span><span class="special">,</span> <span class="keyword">class</span><span class="special">...</span><span class="identifier">Is</span><span class="special">,</span> <span class="keyword">class</span><span class="special">...</span> <span class="identifier">Ks</span><span class="special">,</span> <span class="keyword">class</span> <span class="identifier">Tp</span><span class="special">&gt;</span>
<span class="identifier">R</span> <span class="identifier">tuple_cat_</span><span class="special">(</span> <span class="identifier">mp_list</span><span class="special">&lt;</span><span class="identifier">Is</span><span class="special">...&gt;,</span> <span class="identifier">mp_list</span><span class="special">&lt;</span><span class="identifier">Ks</span><span class="special">...&gt;,</span> <span class="identifier">Tp</span> <span class="identifier">tp</span> <span class="special">)</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">get</span><span class="special">&lt;</span><span class="identifier">Ks</span><span class="special">::</span><span class="identifier">value</span><span class="special">&gt;(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">get</span><span class="special">&lt;</span><span class="identifier">Is</span><span class="special">::</span><span class="identifier">value</span><span class="special">&gt;(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">move</span><span class="special">(</span><span class="identifier">tp</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">remove_cv_ref</span> <span class="special">=</span> <span class="keyword">typename</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">remove_cv</span><span class="special">&lt;</span>
<span class="keyword">typename</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">remove_reference</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">&gt;::</span><span class="identifier">type</span><span class="special">&gt;::</span><span class="identifier">type</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">,</span> <span class="keyword">class</span> <span class="identifier">I</span><span class="special">&gt;</span> <span class="keyword">using</span> <span class="identifier">tuple_element</span> <span class="special">=</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">tuple_element_t</span><span class="special">&lt;</span><span class="identifier">I</span><span class="special">::</span><span class="identifier">value</span><span class="special">,</span> <span class="identifier">T</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">&gt;</span> <span class="keyword">using</span> <span class="identifier">from_tuple_like</span> <span class="special">=</span> <span class="identifier">mp_product</span><span class="special">&lt;</span><span class="identifier">tuple_element</span><span class="special">,</span> <span class="identifier">mp_list</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">&gt;,</span> <span class="identifier">mp_iota</span><span class="special">&lt;</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">tuple_size</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">&gt;&gt;&gt;;</span>
<span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">class</span><span class="special">...</span> <span class="identifier">Tp</span><span class="special">,</span>
<span class="keyword">class</span> <span class="identifier">R</span> <span class="special">=</span> <span class="identifier">mp_append</span><span class="special">&lt;</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">tuple</span><span class="special">&lt;&gt;,</span> <span class="identifier">from_tuple_like</span><span class="special">&lt;</span><span class="identifier">remove_cv_ref</span><span class="special">&lt;</span><span class="identifier">Tp</span><span class="special">&gt;&gt;...&gt;&gt;</span>
<span class="identifier">R</span> <span class="identifier">tuple_cat</span><span class="special">(</span> <span class="identifier">Tp</span> <span class="special">&amp;&amp;...</span> <span class="identifier">tp</span> <span class="special">)</span>
<span class="special">{</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span> <span class="keyword">const</span> <span class="identifier">N</span> <span class="special">=</span> <span class="keyword">sizeof</span><span class="special">...(</span><span class="identifier">Tp</span><span class="special">);</span>
<span class="comment">// inner</span>
<span class="keyword">using</span> <span class="identifier">list1</span> <span class="special">=</span> <span class="identifier">mp_list</span><span class="special">&lt;</span><span class="identifier">from_tuple_like</span><span class="special">&lt;</span><span class="identifier">remove_cv_ref</span><span class="special">&lt;</span><span class="identifier">Tp</span><span class="special">&gt;&gt;...&gt;;</span>
<span class="keyword">using</span> <span class="identifier">list2</span> <span class="special">=</span> <span class="identifier">mp_iota_c</span><span class="special">&lt;</span><span class="identifier">N</span><span class="special">&gt;;</span>
<span class="keyword">using</span> <span class="identifier">list3</span> <span class="special">=</span> <span class="identifier">mp_transform</span><span class="special">&lt;</span><span class="identifier">mp_fill</span><span class="special">,</span> <span class="identifier">list1</span><span class="special">,</span> <span class="identifier">list2</span><span class="special">&gt;;</span>
<span class="keyword">using</span> <span class="identifier">inner</span> <span class="special">=</span> <span class="identifier">mp_apply</span><span class="special">&lt;</span><span class="identifier">mp_append</span><span class="special">,</span> <span class="identifier">list3</span><span class="special">&gt;;</span>
<span class="comment">// outer</span>
<span class="keyword">using</span> <span class="identifier">list4</span> <span class="special">=</span> <span class="identifier">mp_transform</span><span class="special">&lt;</span><span class="identifier">F</span><span class="special">,</span> <span class="identifier">list1</span><span class="special">&gt;;</span>
<span class="keyword">using</span> <span class="identifier">outer</span> <span class="special">=</span> <span class="identifier">mp_apply</span><span class="special">&lt;</span><span class="identifier">mp_append</span><span class="special">,</span> <span class="identifier">list4</span><span class="special">&gt;;</span>
<span class="comment">//</span>
<span class="keyword">return</span> <span class="identifier">tuple_cat_</span><span class="special">&lt;</span><span class="identifier">R</span><span class="special">&gt;(</span> <span class="identifier">inner</span><span class="special">(),</span> <span class="identifier">outer</span><span class="special">(),</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">forward_as_tuple</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">Tp</span><span class="special">&gt;(</span><span class="identifier">tp</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">
@@ -611,6 +864,15 @@
words, <code class="computeroutput"><span class="identifier">mp_size</span><span class="special">&lt;</span><span class="identifier">L</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">...&gt;&gt;</span></code>
is an alias for <code class="computeroutput"><span class="identifier">mp_size_t</span><span class="special">&lt;</span><span class="keyword">sizeof</span><span class="special">...(</span><span class="identifier">T</span><span class="special">)&gt;</span></code>.
</p>
<pre class="programlisting"><span class="keyword">using</span> <span class="identifier">L1</span> <span class="special">=</span> <span class="identifier">mp_list</span><span class="special">&lt;&gt;;</span>
<span class="keyword">using</span> <span class="identifier">R1</span> <span class="special">=</span> <span class="identifier">mp_size</span><span class="special">&lt;</span><span class="identifier">L1</span><span class="special">&gt;;</span> <span class="comment">// mp_size_t&lt;0&gt;</span>
<span class="keyword">using</span> <span class="identifier">L2</span> <span class="special">=</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">pair</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">,</span> <span class="keyword">int</span><span class="special">&gt;;</span>
<span class="keyword">using</span> <span class="identifier">R2</span> <span class="special">=</span> <span class="identifier">mp_size</span><span class="special">&lt;</span><span class="identifier">L2</span><span class="special">&gt;;</span> <span class="comment">// mp_size_t&lt;2&gt;</span>
<span class="keyword">using</span> <span class="identifier">L3</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">float</span><span class="special">&gt;;</span>
<span class="keyword">using</span> <span class="identifier">R3</span> <span class="special">=</span> <span class="identifier">mp_size</span><span class="special">&lt;</span><span class="identifier">L3</span><span class="special">&gt;;</span> <span class="comment">// mp_size_t&lt;1&gt;</span>
</pre>
</div>
<div class="section">
<div class="titlepage"><div><div><h4 class="title">
@@ -637,6 +899,15 @@
That is, <code class="computeroutput"><span class="identifier">mp_front</span><span class="special">&lt;</span><span class="identifier">L</span><span class="special">&lt;</span><span class="identifier">T1</span><span class="special">,</span> <span class="identifier">T</span><span class="special">...&gt;&gt;</span></code>
is an alias for <code class="computeroutput"><span class="identifier">T1</span></code>.
</p>
<pre class="programlisting"><span class="keyword">using</span> <span class="identifier">L1</span> <span class="special">=</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">pair</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="keyword">using</span> <span class="identifier">R1</span> <span class="special">=</span> <span class="identifier">mp_front</span><span class="special">&lt;</span><span class="identifier">L1</span><span class="special">&gt;;</span> <span class="comment">// int</span>
<span class="keyword">using</span> <span class="identifier">L2</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">float</span><span class="special">,</span> <span class="keyword">double</span><span class="special">,</span> <span class="keyword">long</span> <span class="keyword">double</span><span class="special">&gt;;</span>
<span class="keyword">using</span> <span class="identifier">R2</span> <span class="special">=</span> <span class="identifier">mp_front</span><span class="special">&lt;</span><span class="identifier">L2</span><span class="special">&gt;;</span> <span class="comment">// float</span>
<span class="keyword">using</span> <span class="identifier">L3</span> <span class="special">=</span> <span class="identifier">mp_list</span><span class="special">&lt;</span><span class="keyword">char</span><span class="special">[</span><span class="number">1</span><span class="special">],</span> <span class="keyword">char</span><span class="special">[</span><span class="number">2</span><span class="special">],</span> <span class="keyword">char</span><span class="special">[</span><span class="number">3</span><span class="special">],</span> <span class="keyword">char</span><span class="special">[</span><span class="number">4</span><span class="special">]&gt;;</span>
<span class="keyword">using</span> <span class="identifier">R3</span> <span class="special">=</span> <span class="identifier">mp_front</span><span class="special">&lt;</span><span class="identifier">L3</span><span class="special">&gt;;</span> <span class="comment">// char[1]</span>
</pre>
</div>
<div class="section">
<div class="titlepage"><div><div><h4 class="title">
@@ -650,6 +921,12 @@
That is, <code class="computeroutput"><span class="identifier">mp_pop_front</span><span class="special">&lt;</span><span class="identifier">L</span><span class="special">&lt;</span><span class="identifier">T1</span><span class="special">,</span> <span class="identifier">T</span><span class="special">...&gt;&gt;</span></code>
is an alias for <code class="computeroutput"><span class="identifier">L</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">...&gt;</span></code>.
</p>
<pre class="programlisting"><span class="keyword">using</span> <span class="identifier">L1</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">float</span><span class="special">,</span> <span class="keyword">double</span><span class="special">,</span> <span class="keyword">long</span> <span class="keyword">double</span><span class="special">&gt;;</span>
<span class="keyword">using</span> <span class="identifier">R1</span> <span class="special">=</span> <span class="identifier">mp_pop_front</span><span class="special">&lt;</span><span class="identifier">L1</span><span class="special">&gt;;</span> <span class="comment">// std::tuple&lt;double, long double&gt;</span>
<span class="keyword">using</span> <span class="identifier">L2</span> <span class="special">=</span> <span class="identifier">mp_list</span><span class="special">&lt;</span><span class="keyword">void</span><span class="special">&gt;;</span>
<span class="keyword">using</span> <span class="identifier">R2</span> <span class="special">=</span> <span class="identifier">mp_pop_front</span><span class="special">&lt;</span><span class="identifier">L2</span><span class="special">&gt;;</span> <span class="comment">// mp_list&lt;&gt;</span>
</pre>
</div>
<div class="section">
<div class="titlepage"><div><div><h4 class="title">
@@ -685,6 +962,15 @@
That is, <code class="computeroutput"><span class="identifier">mp_second</span><span class="special">&lt;</span><span class="identifier">L</span><span class="special">&lt;</span><span class="identifier">T1</span><span class="special">,</span> <span class="identifier">T2</span><span class="special">,</span> <span class="identifier">T</span><span class="special">...&gt;&gt;</span></code>
is an alias for <code class="computeroutput"><span class="identifier">T2</span></code>.
</p>
<pre class="programlisting"><span class="keyword">using</span> <span class="identifier">L1</span> <span class="special">=</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">pair</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="keyword">using</span> <span class="identifier">R1</span> <span class="special">=</span> <span class="identifier">mp_second</span><span class="special">&lt;</span><span class="identifier">L1</span><span class="special">&gt;;</span> <span class="comment">// float</span>
<span class="keyword">using</span> <span class="identifier">L2</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">float</span><span class="special">,</span> <span class="keyword">double</span><span class="special">,</span> <span class="keyword">long</span> <span class="keyword">double</span><span class="special">&gt;;</span>
<span class="keyword">using</span> <span class="identifier">R2</span> <span class="special">=</span> <span class="identifier">mp_second</span><span class="special">&lt;</span><span class="identifier">L2</span><span class="special">&gt;;</span> <span class="comment">// double</span>
<span class="keyword">using</span> <span class="identifier">L3</span> <span class="special">=</span> <span class="identifier">mp_list</span><span class="special">&lt;</span><span class="keyword">char</span><span class="special">[</span><span class="number">1</span><span class="special">],</span> <span class="keyword">char</span><span class="special">[</span><span class="number">2</span><span class="special">],</span> <span class="keyword">char</span><span class="special">[</span><span class="number">3</span><span class="special">],</span> <span class="keyword">char</span><span class="special">[</span><span class="number">4</span><span class="special">]&gt;;</span>
<span class="keyword">using</span> <span class="identifier">R3</span> <span class="special">=</span> <span class="identifier">mp_second</span><span class="special">&lt;</span><span class="identifier">L3</span><span class="special">&gt;;</span> <span class="comment">// char[2]</span>
</pre>
</div>
<div class="section">
<div class="titlepage"><div><div><h4 class="title">
@@ -698,6 +984,12 @@
That is, <code class="computeroutput"><span class="identifier">mp_third</span><span class="special">&lt;</span><span class="identifier">L</span><span class="special">&lt;</span><span class="identifier">T1</span><span class="special">,</span> <span class="identifier">T2</span><span class="special">,</span> <span class="identifier">T3</span><span class="special">,</span> <span class="identifier">T</span><span class="special">...&gt;&gt;</span></code>
is an alias for <code class="computeroutput"><span class="identifier">T3</span></code>.
</p>
<pre class="programlisting"><span class="keyword">using</span> <span class="identifier">L1</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">float</span><span class="special">,</span> <span class="keyword">double</span><span class="special">,</span> <span class="keyword">long</span> <span class="keyword">double</span><span class="special">&gt;;</span>
<span class="keyword">using</span> <span class="identifier">R1</span> <span class="special">=</span> <span class="identifier">mp_third</span><span class="special">&lt;</span><span class="identifier">L1</span><span class="special">&gt;;</span> <span class="comment">// long double</span>
<span class="keyword">using</span> <span class="identifier">L2</span> <span class="special">=</span> <span class="identifier">mp_list</span><span class="special">&lt;</span><span class="keyword">char</span><span class="special">[</span><span class="number">1</span><span class="special">],</span> <span class="keyword">char</span><span class="special">[</span><span class="number">2</span><span class="special">],</span> <span class="keyword">char</span><span class="special">[</span><span class="number">3</span><span class="special">],</span> <span class="keyword">char</span><span class="special">[</span><span class="number">4</span><span class="special">]&gt;;</span>
<span class="keyword">using</span> <span class="identifier">R2</span> <span class="special">=</span> <span class="identifier">mp_third</span><span class="special">&lt;</span><span class="identifier">L2</span><span class="special">&gt;;</span> <span class="comment">// char[3]</span>
</pre>
</div>
<div class="section">
<div class="titlepage"><div><div><h4 class="title">
@@ -710,6 +1002,12 @@
at the front of the list <code class="computeroutput"><span class="identifier">L</span></code>.
That is, <code class="computeroutput"><span class="identifier">mp_push_front</span><span class="special">&lt;</span><span class="identifier">L</span><span class="special">&lt;</span><span class="identifier">U</span><span class="special">...&gt;,</span> <span class="identifier">T</span><span class="special">...&gt;</span></code> is an alias for <code class="computeroutput"><span class="identifier">L</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">using</span> <span class="identifier">L1</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">double</span><span class="special">,</span> <span class="keyword">long</span> <span class="keyword">double</span><span class="special">&gt;;</span>
<span class="keyword">using</span> <span class="identifier">R1</span> <span class="special">=</span> <span class="identifier">mp_push_front</span><span class="special">&lt;</span><span class="identifier">L1</span><span class="special">,</span> <span class="keyword">float</span><span class="special">&gt;;</span> <span class="comment">// std::tuple&lt;float, double, long double&gt;</span>
<span class="keyword">using</span> <span class="identifier">L2</span> <span class="special">=</span> <span class="identifier">mp_list</span><span class="special">&lt;</span><span class="keyword">void</span><span class="special">&gt;;</span>
<span class="keyword">using</span> <span class="identifier">R2</span> <span class="special">=</span> <span class="identifier">mp_push_front</span><span class="special">&lt;</span><span class="identifier">L2</span><span class="special">,</span> <span class="keyword">char</span><span class="special">[</span><span class="number">1</span><span class="special">],</span> <span class="keyword">char</span><span class="special">[</span><span class="number">2</span><span class="special">]&gt;;</span> <span class="comment">// mp_list&lt;char[1], char[2], void&gt;</span>
</pre>
</div>
<div class="section">
<div class="titlepage"><div><div><h4 class="title">
@@ -723,6 +1021,12 @@
That is, <code class="computeroutput"><span class="identifier">mp_push_back</span><span class="special">&lt;</span><span class="identifier">L</span><span class="special">&lt;</span><span class="identifier">U</span><span class="special">...&gt;,</span> <span class="identifier">T</span><span class="special">...&gt;</span></code>
is an alias for <code class="computeroutput"><span class="identifier">L</span><span class="special">&lt;</span><span class="identifier">U</span><span class="special">...,</span> <span class="identifier">T</span><span class="special">...&gt;</span></code>.
</p>
<pre class="programlisting"><span class="keyword">using</span> <span class="identifier">L1</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">double</span><span class="special">,</span> <span class="keyword">long</span> <span class="keyword">double</span><span class="special">&gt;;</span>
<span class="keyword">using</span> <span class="identifier">R1</span> <span class="special">=</span> <span class="identifier">mp_push_back</span><span class="special">&lt;</span><span class="identifier">L1</span><span class="special">,</span> <span class="keyword">float</span><span class="special">&gt;;</span> <span class="comment">// std::tuple&lt;double, long double, float&gt;</span>
<span class="keyword">using</span> <span class="identifier">L2</span> <span class="special">=</span> <span class="identifier">mp_list</span><span class="special">&lt;</span><span class="keyword">void</span><span class="special">&gt;;</span>
<span class="keyword">using</span> <span class="identifier">R2</span> <span class="special">=</span> <span class="identifier">mp_push_back</span><span class="special">&lt;</span><span class="identifier">L2</span><span class="special">,</span> <span class="keyword">char</span><span class="special">[</span><span class="number">1</span><span class="special">],</span> <span class="keyword">char</span><span class="special">[</span><span class="number">2</span><span class="special">]&gt;;</span> <span class="comment">// mp_list&lt;void, char[1], char[2]&gt;</span>
</pre>
</div>
<div class="section">
<div class="titlepage"><div><div><h4 class="title">
@@ -736,6 +1040,12 @@
That is, <code class="computeroutput"><span class="identifier">mp_rename</span><span class="special">&lt;</span><span class="identifier">L</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">...&gt;,</span> <span class="identifier">Y</span><span class="special">&gt;</span></code>
is an alias for <code class="computeroutput"><span class="identifier">Y</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">...&gt;</span></code>.
</p>
<pre class="programlisting"><span class="keyword">using</span> <span class="identifier">L1</span> <span class="special">=</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">pair</span><span class="special">&lt;</span><span class="keyword">double</span><span class="special">,</span> <span class="keyword">long</span> <span class="keyword">double</span><span class="special">&gt;;</span>
<span class="keyword">using</span> <span class="identifier">R1</span> <span class="special">=</span> <span class="identifier">mp_rename</span><span class="special">&lt;</span><span class="identifier">L1</span><span class="special">,</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">tuple</span><span class="special">&gt;;</span> <span class="comment">// std::tuple&lt;double, long double&gt;</span>
<span class="keyword">using</span> <span class="identifier">L2</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">void</span><span class="special">&gt;;</span>
<span class="keyword">using</span> <span class="identifier">R2</span> <span class="special">=</span> <span class="identifier">mp_rename</span><span class="special">&lt;</span><span class="identifier">L2</span><span class="special">,</span> <span class="identifier">mp_list</span><span class="special">&gt;;</span> <span class="comment">// mp_list&lt;void&gt;</span>
</pre>
</div>
<div class="section">
<div class="titlepage"><div><div><h4 class="title">
@@ -751,6 +1061,9 @@
<code class="computeroutput"><span class="identifier">mp_rename</span></code> with the arguments
reversed.)
</p>
<pre class="programlisting"><span class="keyword">using</span> <span class="identifier">L1</span> <span class="special">=</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">pair</span><span class="special">&lt;</span><span class="keyword">double</span><span class="special">,</span> <span class="keyword">long</span> <span class="keyword">double</span><span class="special">&gt;;</span>
<span class="keyword">using</span> <span class="identifier">R1</span> <span class="special">=</span> <span class="identifier">mp_apply</span><span class="special">&lt;</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">is_same</span><span class="special">,</span> <span class="identifier">L1</span><span class="special">&gt;;</span> <span class="comment">// std::is_same&lt;double, long double&gt;</span>
</pre>
</div>
<div class="section">
<div class="titlepage"><div><div><h4 class="title">
@@ -763,6 +1076,10 @@
Same as <code class="computeroutput"><span class="identifier">mp_apply</span></code>, but takes
a quoted metafunction.
</p>
<pre class="programlisting"><span class="keyword">using</span> <span class="identifier">L1</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">double</span><span class="special">,</span> <span class="keyword">long</span> <span class="keyword">double</span><span class="special">&gt;;</span>
<span class="keyword">using</span> <span class="identifier">L2</span> <span class="special">=</span> <span class="identifier">mp_list</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">,</span> <span class="keyword">long</span><span class="special">&gt;;</span>
<span class="keyword">using</span> <span class="identifier">R1</span> <span class="special">=</span> <span class="identifier">mp_apply_q</span><span class="special">&lt;</span><span class="identifier">mp_bind_front</span><span class="special">&lt;</span><span class="identifier">mp_push_back</span><span class="special">,</span> <span class="identifier">L1</span><span class="special">&gt;,</span> <span class="identifier">L2</span><span class="special">&gt;;</span> <span class="comment">// std::tuple&lt;double, long double, int, long&gt;</span>
</pre>
</div>
<div class="section">
<div class="titlepage"><div><div><h4 class="title">
@@ -777,6 +1094,13 @@
<span class="identifier">Ln</span><span class="special">&lt;</span><span class="identifier">Tn</span><span class="special">...&gt;&gt;</span></code>
is an alias for <code class="computeroutput"><span class="identifier">L1</span><span class="special">&lt;</span><span class="identifier">T1</span><span class="special">...,</span> <span class="identifier">T2</span><span class="special">...,</span> <span class="special">...,</span> <span class="identifier">Tn</span><span class="special">...&gt;</span></code>.
</p>
<pre class="programlisting"><span class="keyword">using</span> <span class="identifier">L1</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">double</span><span class="special">,</span> <span class="keyword">long</span> <span class="keyword">double</span><span class="special">&gt;;</span>
<span class="keyword">using</span> <span class="identifier">L2</span> <span class="special">=</span> <span class="identifier">mp_list</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">&gt;;</span>
<span class="keyword">using</span> <span class="identifier">L3</span> <span class="special">=</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">pair</span><span class="special">&lt;</span><span class="keyword">short</span><span class="special">,</span> <span class="keyword">long</span><span class="special">&gt;;</span>
<span class="keyword">using</span> <span class="identifier">L4</span> <span class="special">=</span> <span class="identifier">mp_list</span><span class="special">&lt;&gt;;</span>
<span class="keyword">using</span> <span class="identifier">R1</span> <span class="special">=</span> <span class="identifier">mp_append</span><span class="special">&lt;</span><span class="identifier">L1</span><span class="special">,</span> <span class="identifier">L2</span><span class="special">,</span> <span class="identifier">L3</span><span class="special">,</span> <span class="identifier">L4</span><span class="special">&gt;;</span> <span class="comment">// std::tuple&lt;double, long double, int, short, long&gt;</span>
</pre>
</div>
<div class="section">
<div class="titlepage"><div><div><h4 class="title">
@@ -791,6 +1115,15 @@
<span class="identifier">T</span><span class="special">&gt;</span></code>
is an alias for <code class="computeroutput"><span class="identifier">L</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">using</span> <span class="identifier">L1</span> <span class="special">=</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">pair</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="keyword">using</span> <span class="identifier">R1</span> <span class="special">=</span> <span class="identifier">mp_replace_front</span><span class="special">&lt;</span><span class="identifier">L1</span><span class="special">,</span> <span class="keyword">void</span><span class="special">&gt;;</span> <span class="comment">// std::pair&lt;void, float&gt;</span>
<span class="keyword">using</span> <span class="identifier">L2</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">float</span><span class="special">,</span> <span class="keyword">double</span><span class="special">,</span> <span class="keyword">long</span> <span class="keyword">double</span><span class="special">&gt;;</span>
<span class="keyword">using</span> <span class="identifier">R2</span> <span class="special">=</span> <span class="identifier">mp_replace_front</span><span class="special">&lt;</span><span class="identifier">L2</span><span class="special">,</span> <span class="keyword">void</span><span class="special">&gt;;</span> <span class="comment">// std::tuple&lt;void, double, long double&gt;</span>
<span class="keyword">using</span> <span class="identifier">L3</span> <span class="special">=</span> <span class="identifier">mp_list</span><span class="special">&lt;</span><span class="keyword">char</span><span class="special">[</span><span class="number">1</span><span class="special">],</span> <span class="keyword">char</span><span class="special">[</span><span class="number">2</span><span class="special">],</span> <span class="keyword">char</span><span class="special">[</span><span class="number">3</span><span class="special">],</span> <span class="keyword">char</span><span class="special">[</span><span class="number">4</span><span class="special">]&gt;;</span>
<span class="keyword">using</span> <span class="identifier">R3</span> <span class="special">=</span> <span class="identifier">mp_replace_front</span><span class="special">&lt;</span><span class="identifier">L3</span><span class="special">,</span> <span class="keyword">void</span><span class="special">&gt;;</span> <span class="comment">// mp_list&lt;void, char[2], char[3], char[4]&gt;;</span>
</pre>
</div>
<div class="section">
<div class="titlepage"><div><div><h4 class="title">
@@ -815,6 +1148,15 @@
<span class="identifier">T</span><span class="special">&gt;</span></code>
is an alias for <code class="computeroutput"><span class="identifier">L</span><span class="special">&lt;</span><span class="identifier">U1</span><span class="special">,</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">using</span> <span class="identifier">L1</span> <span class="special">=</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">pair</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="keyword">using</span> <span class="identifier">R1</span> <span class="special">=</span> <span class="identifier">mp_replace_second</span><span class="special">&lt;</span><span class="identifier">L1</span><span class="special">,</span> <span class="keyword">void</span><span class="special">&gt;;</span> <span class="comment">// std::pair&lt;int, void&gt;</span>
<span class="keyword">using</span> <span class="identifier">L2</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">float</span><span class="special">,</span> <span class="keyword">double</span><span class="special">,</span> <span class="keyword">long</span> <span class="keyword">double</span><span class="special">&gt;;</span>
<span class="keyword">using</span> <span class="identifier">R2</span> <span class="special">=</span> <span class="identifier">mp_replace_second</span><span class="special">&lt;</span><span class="identifier">L2</span><span class="special">,</span> <span class="keyword">void</span><span class="special">&gt;;</span> <span class="comment">// std::tuple&lt;float, void, long double&gt;</span>
<span class="keyword">using</span> <span class="identifier">L3</span> <span class="special">=</span> <span class="identifier">mp_list</span><span class="special">&lt;</span><span class="keyword">char</span><span class="special">[</span><span class="number">1</span><span class="special">],</span> <span class="keyword">char</span><span class="special">[</span><span class="number">2</span><span class="special">],</span> <span class="keyword">char</span><span class="special">[</span><span class="number">3</span><span class="special">],</span> <span class="keyword">char</span><span class="special">[</span><span class="number">4</span><span class="special">]&gt;;</span>
<span class="keyword">using</span> <span class="identifier">R3</span> <span class="special">=</span> <span class="identifier">mp_replace_second</span><span class="special">&lt;</span><span class="identifier">L3</span><span class="special">,</span> <span class="keyword">void</span><span class="special">&gt;;</span> <span class="comment">// mp_list&lt;char[1], void, char[3], char[4]&gt;;</span>
</pre>
</div>
<div class="section">
<div class="titlepage"><div><div><h4 class="title">
@@ -829,6 +1171,12 @@
<span class="identifier">T</span><span class="special">&gt;</span></code>
is an alias for <code class="computeroutput"><span class="identifier">L</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="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">using</span> <span class="identifier">L1</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">float</span><span class="special">,</span> <span class="keyword">double</span><span class="special">,</span> <span class="keyword">long</span> <span class="keyword">double</span><span class="special">&gt;;</span>
<span class="keyword">using</span> <span class="identifier">R1</span> <span class="special">=</span> <span class="identifier">mp_replace_third</span><span class="special">&lt;</span><span class="identifier">L1</span><span class="special">,</span> <span class="keyword">void</span><span class="special">&gt;;</span> <span class="comment">// std::tuple&lt;float, double, void&gt;</span>
<span class="keyword">using</span> <span class="identifier">L2</span> <span class="special">=</span> <span class="identifier">mp_list</span><span class="special">&lt;</span><span class="keyword">char</span><span class="special">[</span><span class="number">1</span><span class="special">],</span> <span class="keyword">char</span><span class="special">[</span><span class="number">2</span><span class="special">],</span> <span class="keyword">char</span><span class="special">[</span><span class="number">3</span><span class="special">],</span> <span class="keyword">char</span><span class="special">[</span><span class="number">4</span><span class="special">]&gt;;</span>
<span class="keyword">using</span> <span class="identifier">R2</span> <span class="special">=</span> <span class="identifier">mp_replace_third</span><span class="special">&lt;</span><span class="identifier">L2</span><span class="special">,</span> <span class="keyword">void</span><span class="special">&gt;;</span> <span class="comment">// mp_list&lt;char[1], char[2], void, char[4]&gt;;</span>
</pre>
</div>
</div>
<div class="section">
@@ -1951,7 +2299,7 @@
</div>
</div>
<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
<td align="left"><p><small>Last revised: May 13, 2017 at 18:21:04 GMT</small></p></td>
<td align="left"><p><small>Last revised: May 17, 2017 at 17:44:23 GMT</small></p></td>
<td align="right"><div class="copyright-footer"></div></td>
</tr></table>
<hr>

View File

@@ -73,6 +73,186 @@ how we can leverage Mp11 to automate the task:
boost::tuple_for_each( mp_product<mp_list, L, L>(), [](auto&& x){ test_result(x); } );
}
How does it work?
`mp_product<F, L1, L2>` calls `F<T1, T2>` where `T1` varies over the elements of `L1` and `T2` varies over
the elements of `L2`, as if by executing two nested loops. It then returns a list of these results, of the same
type as `L1`.
In our case, both lists are the same `std::tuple`, and `F` is `mp_list`, so `mp_product<mp_list, L, L>` will get us
`std::tuple<mp_list<char, char>, mp_list<char, short>, mp_list<char, int>, ..., mp_list<unsigned long, long>, mp_list<unsigned long, unsigned long>>`.
We then default-construct this tuple and pass it to `tuple_for_each`. `tuple_for_each(tp, f)` calls `f` for every
tuple element; we use a (C++14) lambda that calls `test_result`. (In pure C++11, we'd need to make `test_result` a
function object with a templated `operator()` and pass that to `tuple_for_each` directly.)
[endsect]
[section Fixing `tuple_cat`]
The article [@http://pdimov.com/cpp2/simple_cxx11_metaprogramming.html Simple C++11 metaprogramming] builds an
implementation of the standard function `tuple_cat`, with the end result given below:
template<class L> using F = mp_iota<mp_size<L>>;
template<class R, class...Is, class... Ks, class Tp>
R tuple_cat_( mp_list<Is...>, mp_list<Ks...>, Tp tp )
{
return R{ std::get<Ks::value>(std::get<Is::value>(tp))... };
}
template<class... Tp,
class R = mp_append<std::tuple<>, typename std::remove_reference<Tp>::type...>>
R tuple_cat( Tp &&... tp )
{
std::size_t const N = sizeof...(Tp);
// inner
using list1 = mp_list<mp_rename<typename std::remove_reference<Tp>::type, mp_list>...>;
using list2 = mp_iota_c<N>;
using list3 = mp_transform<mp_fill, list1, list2>;
using inner = mp_apply<mp_append, list3>;
// outer
using list4 = mp_transform<F, list1>;
using outer = mp_apply<mp_append, list4>;
//
return tuple_cat_<R>( inner(), outer(), std::forward_as_tuple( std::forward<Tp>(tp)... ) );
}
This function, however, is not entirely correct, in that it doesn't handle some cases properly. For example,
trying to concatenate tuples containing move-only elements such as `unique_ptr` fails:
std::tuple<std::unique_ptr<int>> t1;
std::tuple<std::unique_ptr<float>> t2;
auto result = ::tuple_cat( std::move( t1 ), std::move( t2 ) );
Trying to concatenate `const` tuples fails:
std::tuple<int> const t1;
std::tuple<float> const t2;
auto result = ::tuple_cat( t1, t2 );
And finally, the standard `tuple_cat` is specified to work on arbitrary tuple-like types (that is, all types
that support `tuple_size`, `tuple_element`, and `get`), while our implementation only works with `tuple` and
`pair`. `std::array`, for example, fails:
std::array<int, 2> t1{ 1, 2 };
std::array<float, 3> t2{ 3.0f, 4.0f, 5.0f };
auto result = ::tuple_cat( t1, std::move( t2 ) );
Let's fix these one by one. Support for move-only types is easy, if one knows where to look. The problem is
that `Tp` that we're passing to the helper `tuple_cat_` is (correctly) `tuple<unique_ptr<int>&&, unique_ptr<float>&&>`,
but `std::get<0>(tp)` still returns `unique_ptr<int>&`, because `tp` is an lvalue. This behavior is a bit
surprising, but consistent with how rvalue reference members are treated by the language.
Long story short, we need `std::move(tp)` in `tuple_cat_` to make `tp` an rvalue:
template<class R, class...Is, class... Ks, class Tp>
R tuple_cat_( mp_list<Is...>, mp_list<Ks...>, Tp tp )
{
return R{ std::get<Ks::value>(std::get<Is::value>(std::move(tp)))... };
}
Next, `const`-qualified tuples. The issue here is that we're stripping references from the input tuples, but not
`const`. As a result, we're trying to manipulate types such as `tuple<int> const` with Mp11 algorithms, and these
types do not fit the list concept. We just need to strip qualifiers as well, by defining the useful `remove_cv_ref`
primitive that is inexplicably missing from the standard library:
template<class T> using remove_cv_ref = typename std::remove_cv<
typename std::remove_reference<T>::type>::type;
and then by using `remove_cv_ref<Tp>` in place of `typename std::remove_reference<Tp>::type`:
template<class... Tp,
class R = mp_append<std::tuple<>, remove_cv_ref<Tp>...>>
R tuple_cat( Tp &&... tp )
{
std::size_t const N = sizeof...(Tp);
// inner
using list1 = mp_list<mp_rename<remove_cv_ref<Tp>, mp_list>...>;
// ...
Finally, tuple-like types. We've so far exploited the fact that `std::pair` and `std::tuple` are valid Mp11 lists,
but in general, arbitrary tuple-like types aren't, so we need to convert them into such. For that, we'll need to
define a metafunction `from_tuple_like` that will take an arbitrary tuple-like type and will return, in our case,
the corresponding `mp_list`.
Technically, a more principled approach would've been to return `std::tuple`, but here `mp_list` will prove more
convenient.
What we need is, given a tuple-like type `Tp`, to obtain `mp_list<std::tuple_element<0, Tp>, std::tuple_element<1, Tp>,
..., std::tuple_element<N-1, Tp>>`, where `N` is `tuple_size<Tp>::value`. Here's one way to do it:
template<class T, class I> using tuple_element = std::tuple_element_t<I::value, T>;
template<class T> using from_tuple_like = mp_product<tuple_element, mp_list<T>, mp_iota<std::tuple_size<T>>>;
(`mp_iota<N>` is an algorithm that returns an `mp_list` with elements `mp_size_t<0>`, `mp_size_t<1>`, ..., `mp_size_t<N-1>`.)
Remember that `mp_product<F, L1, L2>` performs the equivalent of two nested loops over the elements of `L1` and `L2`,
applying `F` to the two variables and gathering the result. In our case `L1` consists of the single element `T`, so
only the second loop (over `mp_iota<N>`, where `N` is `tuple_size<T>`), remains, and we get a list of the same type
as `L1` (an `mp_list`) with contents `tuple_element<T, mp_size_t<0>>`, `tuple_element<T, mp_size_t<1>>`, ...,
`tuple_element<T, mp_size_t<N-1>>`.
For completeness's sake, here's another, more traditional way to achieve the same result:
template<class T> using from_tuple_like = mp_transform_q<mp_bind_front<tuple_element, T>, mp_iota<std::tuple_size<T>>>;
With all these fixes applied, our fully operational `tuple_cat` now looks like this:
template<class L> using F = mp_iota<mp_size<L>>;
template<class R, class...Is, class... Ks, class Tp>
R tuple_cat_( mp_list<Is...>, mp_list<Ks...>, Tp tp )
{
return R{ std::get<Ks::value>(std::get<Is::value>(std::move(tp)))... };
}
template<class T> using remove_cv_ref = typename std::remove_cv<
typename std::remove_reference<T>::type>::type;
template<class T, class I> using tuple_element = std::tuple_element_t<I::value, T>;
template<class T> using from_tuple_like = mp_product<tuple_element, mp_list<T>, mp_iota<std::tuple_size<T>>>;
template<class... Tp,
class R = mp_append<std::tuple<>, from_tuple_like<remove_cv_ref<Tp>>...>>
R tuple_cat( Tp &&... tp )
{
std::size_t const N = sizeof...(Tp);
// inner
using list1 = mp_list<from_tuple_like<remove_cv_ref<Tp>>...>;
using list2 = mp_iota_c<N>;
using list3 = mp_transform<mp_fill, list1, list2>;
using inner = mp_apply<mp_append, list3>;
// outer
using list4 = mp_transform<F, list1>;
using outer = mp_apply<mp_append, list4>;
//
return tuple_cat_<R>( inner(), outer(), std::forward_as_tuple( std::forward<Tp>(tp)... ) );
}
[endsect]
[section Computing Return Types]

View File

@@ -21,6 +21,15 @@ the list.
`mp_size<L>` returns the number of elements in the list `L`, as a `mp_size_t`. In other words, `mp_size<L<T...>>` is an alias for
`mp_size_t<sizeof...(T)>`.
using L1 = mp_list<>;
using R1 = mp_size<L1>; // mp_size_t<0>
using L2 = std::pair<int, int>;
using R2 = mp_size<L2>; // mp_size_t<2>
using L3 = std::tuple<float>;
using R3 = mp_size<L3>; // mp_size_t<1>
[endsect]
[section `mp_empty<L>`]
@@ -33,12 +42,27 @@ the list.
template<class L> using mp_front = /*...*/;
`mp_front<L>` is the first element of the list `L`. That is, `mp_front<L<T1, T...>>` is an alias for `T1`.
using L1 = std::pair<int, float>;
using R1 = mp_front<L1>; // int
using L2 = std::tuple<float, double, long double>;
using R2 = mp_front<L2>; // float
using L3 = mp_list<char[1], char[2], char[3], char[4]>;
using R3 = mp_front<L3>; // char[1]
[endsect]
[section `mp_pop_front<L>`]
template<class L> using mp_pop_front = /*...*/;
`mp_pop_front<L>` removes the first element of the list `L`. That is, `mp_pop_front<L<T1, T...>>` is an alias for `L<T...>`.
using L1 = std::tuple<float, double, long double>;
using R1 = mp_pop_front<L1>; // std::tuple<double, long double>
using L2 = mp_list<void>;
using R2 = mp_pop_front<L2>; // mp_list<>
[endsect]
[section `mp_first<L>`]
@@ -57,12 +81,27 @@ the list.
template<class L> using mp_second = /*...*/;
`mp_second<L>` is the second element of the list `L`. That is, `mp_second<L<T1, T2, T...>>` is an alias for `T2`.
using L1 = std::pair<int, float>;
using R1 = mp_second<L1>; // float
using L2 = std::tuple<float, double, long double>;
using R2 = mp_second<L2>; // double
using L3 = mp_list<char[1], char[2], char[3], char[4]>;
using R3 = mp_second<L3>; // char[2]
[endsect]
[section `mp_third<L>`]
template<class L> using mp_third = /*...*/;
`mp_third<L>` is the third element of the list `L`. That is, `mp_third<L<T1, T2, T3, T...>>` is an alias for `T3`.
using L1 = std::tuple<float, double, long double>;
using R1 = mp_third<L1>; // long double
using L2 = mp_list<char[1], char[2], char[3], char[4]>;
using R2 = mp_third<L2>; // char[3]
[endsect]
[section `mp_push_front<L, T...>`]
@@ -70,6 +109,12 @@ the list.
`mp_push_front<L, T...>` inserts the elements `T...` at the front of the list `L`. That is, `mp_push_front<L<U...>, T...>`
is an alias for `L<T..., U...>`.
using L1 = std::tuple<double, long double>;
using R1 = mp_push_front<L1, float>; // std::tuple<float, double, long double>
using L2 = mp_list<void>;
using R2 = mp_push_front<L2, char[1], char[2]>; // mp_list<char[1], char[2], void>
[endsect]
[section `mp_push_back<L, T...>`]
@@ -77,12 +122,24 @@ is an alias for `L<T..., U...>`.
`mp_push_back<L, T...>` inserts the elements `T...` at the back of the list `L`. That is, `mp_push_back<L<U...>, T...>`
is an alias for `L<U..., T...>`.
using L1 = std::tuple<double, long double>;
using R1 = mp_push_back<L1, float>; // std::tuple<double, long double, float>
using L2 = mp_list<void>;
using R2 = mp_push_back<L2, char[1], char[2]>; // mp_list<void, char[1], char[2]>
[endsect]
[section `mp_rename<L, Y>`]
template<class L, template<class...> class Y> using mp_rename = /*...*/;
`mp_rename<L, Y>` changes the type of the list `L` to `Y`. That is, `mp_rename<L<T...>, Y>` is an alias for `Y<T...>`.
using L1 = std::pair<double, long double>;
using R1 = mp_rename<L1, std::tuple>; // std::tuple<double, long double>
using L2 = std::tuple<void>;
using R2 = mp_rename<L2, mp_list>; // mp_list<void>
[endsect]
[section `mp_apply<F, L>`]
@@ -90,12 +147,19 @@ is an alias for `L<U..., T...>`.
`mp_apply<F, L>` applies the metafunction `F` to the contents of the list `L`, that is, `mp_apply<F, L<T...>>` is an alias for `F<T...>`.
(`mp_apply` is the same as `mp_rename` with the arguments reversed.)
using L1 = std::pair<double, long double>;
using R1 = mp_apply<std::is_same, L1>; // std::is_same<double, long double>
[endsect]
[section `mp_apply_q<Q, L>`]
template<class Q, class L> using mp_apply_q = mp_apply<Q::template fn, L>;
Same as `mp_apply`, but takes a quoted metafunction.
using L1 = std::tuple<double, long double>;
using L2 = mp_list<int, long>;
using R1 = mp_apply_q<mp_bind_front<mp_push_back, L1>, L2>; // std::tuple<double, long double, int, long>
[endsect]
[section `mp_append<L...>`]
@@ -103,6 +167,13 @@ Same as `mp_apply`, but takes a quoted metafunction.
`mp_append<L...>` concatenates the lists in `L...` into a single list that has the same type as the first list. `mp_append<>`
is an alias for `mp_list<>`. `mp_append<L1<T1...>, L2<T2...>, ..., Ln<Tn...>>` is an alias for `L1<T1..., T2..., ..., Tn...>`.
using L1 = std::tuple<double, long double>;
using L2 = mp_list<int>;
using L3 = std::pair<short, long>;
using L4 = mp_list<>;
using R1 = mp_append<L1, L2, L3, L4>; // std::tuple<double, long double, int, short, long>
[endsect]
[section `mp_replace_front<L, T>`]
@@ -110,6 +181,15 @@ is an alias for `mp_list<>`. `mp_append<L1<T1...>, L2<T2...>, ..., Ln<Tn...>>` i
`mp_replace_front<L, T>` replaces the first element of the list `L` with `T`. That is, `mp_replace_front<L<U1, U...>, T>` is
an alias for `L<T, U...>`.
using L1 = std::pair<int, float>;
using R1 = mp_replace_front<L1, void>; // std::pair<void, float>
using L2 = std::tuple<float, double, long double>;
using R2 = mp_replace_front<L2, void>; // std::tuple<void, double, long double>
using L3 = mp_list<char[1], char[2], char[3], char[4]>;
using R3 = mp_replace_front<L3, void>; // mp_list<void, char[2], char[3], char[4]>;
[endsect]
[section `mp_replace_first<L, T>`]
@@ -123,6 +203,15 @@ an alias for `L<T, U...>`.
`mp_replace_second<L, T>` replaces the second element of the list `L` with `T`. That is, `mp_replace_second<L<U1, U2, U...>, T>`
is an alias for `L<U1, T, U...>`.
using L1 = std::pair<int, float>;
using R1 = mp_replace_second<L1, void>; // std::pair<int, void>
using L2 = std::tuple<float, double, long double>;
using R2 = mp_replace_second<L2, void>; // std::tuple<float, void, long double>
using L3 = mp_list<char[1], char[2], char[3], char[4]>;
using R3 = mp_replace_second<L3, void>; // mp_list<char[1], void, char[3], char[4]>;
[endsect]
[section `mp_replace_third<L, T>`]
@@ -130,6 +219,12 @@ is an alias for `L<U1, T, U...>`.
`mp_replace_third<L, T>` replaces the third element of the list `L` with `T`. That is, `mp_replace_third<L<U1, U2, U3, U...>, T>`
is an alias for `L<U1, U2, T, U...>`.
using L1 = std::tuple<float, double, long double>;
using R1 = mp_replace_third<L1, void>; // std::tuple<float, double, void>
using L2 = mp_list<char[1], char[2], char[3], char[4]>;
using R2 = mp_replace_third<L2, void>; // mp_list<char[1], char[2], void, char[4]>;
[endsect]
[endsect:list]