forked from boostorg/mp11
Merge branch 'develop'
This commit is contained in:
@@ -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"><</span><span class="identifier">mp_list</span><span class="special">,</span> <span class="identifier">L</span><span class="special">,</span> <span class="identifier">L</span><span class="special">>(),</span> <span class="special">[](</span><span class="keyword">auto</span><span class="special">&&</span> <span class="identifier">x</span><span class="special">){</span> <span class="identifier">test_result</span><span class="special">(</span><span class="identifier">x</span><span class="special">);</span> <span class="special">}</span> <span class="special">);</span>
|
||||
<span class="special">}</span>
|
||||
</pre>
|
||||
<p>
|
||||
How does it work?
|
||||
</p>
|
||||
<p>
|
||||
<code class="computeroutput"><span class="identifier">mp_product</span><span class="special"><</span><span class="identifier">F</span><span class="special">,</span> <span class="identifier">L1</span><span class="special">,</span> <span class="identifier">L2</span><span class="special">></span></code>
|
||||
calls <code class="computeroutput"><span class="identifier">F</span><span class="special"><</span><span class="identifier">T1</span><span class="special">,</span> <span class="identifier">T2</span><span class="special">></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"><</span><span class="identifier">mp_list</span><span class="special">,</span> <span class="identifier">L</span><span class="special">,</span> <span class="identifier">L</span><span class="special">></span></code> will get us <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">tuple</span><span class="special"><</span><span class="identifier">mp_list</span><span class="special"><</span><span class="keyword">char</span><span class="special">,</span>
|
||||
<span class="keyword">char</span><span class="special">>,</span>
|
||||
<span class="identifier">mp_list</span><span class="special"><</span><span class="keyword">char</span><span class="special">,</span> <span class="keyword">short</span><span class="special">>,</span> <span class="identifier">mp_list</span><span class="special"><</span><span class="keyword">char</span><span class="special">,</span>
|
||||
<span class="keyword">int</span><span class="special">>,</span>
|
||||
<span class="special">...,</span> <span class="identifier">mp_list</span><span class="special"><</span><span class="keyword">unsigned</span> <span class="keyword">long</span><span class="special">,</span> <span class="keyword">long</span><span class="special">>,</span> <span class="identifier">mp_list</span><span class="special"><</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">>></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"><</span><span class="keyword">class</span> <span class="identifier">L</span><span class="special">></span> <span class="keyword">using</span> <span class="identifier">F</span> <span class="special">=</span> <span class="identifier">mp_iota</span><span class="special"><</span><span class="identifier">mp_size</span><span class="special"><</span><span class="identifier">L</span><span class="special">>>;</span>
|
||||
|
||||
<span class="keyword">template</span><span class="special"><</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">></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"><</span><span class="identifier">Is</span><span class="special">...>,</span> <span class="identifier">mp_list</span><span class="special"><</span><span class="identifier">Ks</span><span class="special">...>,</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"><</span><span class="identifier">Ks</span><span class="special">::</span><span class="identifier">value</span><span class="special">>(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">get</span><span class="special"><</span><span class="identifier">Is</span><span class="special">::</span><span class="identifier">value</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"><</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"><</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">tuple</span><span class="special"><>,</span> <span class="keyword">typename</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">remove_reference</span><span class="special"><</span><span class="identifier">Tp</span><span class="special">>::</span><span class="identifier">type</span><span class="special">...>></span>
|
||||
<span class="identifier">R</span> <span class="identifier">tuple_cat</span><span class="special">(</span> <span class="identifier">Tp</span> <span class="special">&&...</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"><</span><span class="identifier">mp_rename</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">remove_reference</span><span class="special"><</span><span class="identifier">Tp</span><span class="special">>::</span><span class="identifier">type</span><span class="special">,</span> <span class="identifier">mp_list</span><span class="special">>...>;</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"><</span><span class="identifier">N</span><span class="special">>;</span>
|
||||
|
||||
<span class="keyword">using</span> <span class="identifier">list3</span> <span class="special">=</span> <span class="identifier">mp_transform</span><span class="special"><</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">>;</span>
|
||||
|
||||
<span class="keyword">using</span> <span class="identifier">inner</span> <span class="special">=</span> <span class="identifier">mp_apply</span><span class="special"><</span><span class="identifier">mp_append</span><span class="special">,</span> <span class="identifier">list3</span><span class="special">>;</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"><</span><span class="identifier">F</span><span class="special">,</span> <span class="identifier">list1</span><span class="special">>;</span>
|
||||
|
||||
<span class="keyword">using</span> <span class="identifier">outer</span> <span class="special">=</span> <span class="identifier">mp_apply</span><span class="special"><</span><span class="identifier">mp_append</span><span class="special">,</span> <span class="identifier">list4</span><span class="special">>;</span>
|
||||
|
||||
<span class="comment">//</span>
|
||||
|
||||
<span class="keyword">return</span> <span class="identifier">tuple_cat_</span><span class="special"><</span><span class="identifier">R</span><span class="special">>(</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"><</span><span class="identifier">Tp</span><span class="special">>(</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"><</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">unique_ptr</span><span class="special"><</span><span class="keyword">int</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">tuple</span><span class="special"><</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">unique_ptr</span><span class="special"><</span><span class="keyword">float</span><span class="special">>></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"><</span><span class="keyword">int</span><span class="special">></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"><</span><span class="keyword">float</span><span class="special">></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"><</span><span class="keyword">int</span><span class="special">,</span> <span class="number">2</span><span class="special">></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"><</span><span class="keyword">float</span><span class="special">,</span> <span class="number">3</span><span class="special">></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"><</span><span class="identifier">unique_ptr</span><span class="special"><</span><span class="keyword">int</span><span class="special">>&&,</span>
|
||||
<span class="identifier">unique_ptr</span><span class="special"><</span><span class="keyword">float</span><span class="special">>&&></span></code>,
|
||||
but <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">get</span><span class="special"><</span><span class="number">0</span><span class="special">>(</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"><</span><span class="keyword">int</span><span class="special">>&</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"><</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">></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"><</span><span class="identifier">Is</span><span class="special">...>,</span> <span class="identifier">mp_list</span><span class="special"><</span><span class="identifier">Ks</span><span class="special">...>,</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"><</span><span class="identifier">Ks</span><span class="special">::</span><span class="identifier">value</span><span class="special">>(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">get</span><span class="special"><</span><span class="identifier">Is</span><span class="special">::</span><span class="identifier">value</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">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"><</span><span class="keyword">int</span><span class="special">></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"><</span><span class="keyword">class</span> <span class="identifier">T</span><span class="special">></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"><</span>
|
||||
<span class="keyword">typename</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">remove_reference</span><span class="special"><</span><span class="identifier">T</span><span class="special">>::</span><span class="identifier">type</span><span class="special">>::</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"><</span><span class="identifier">Tp</span><span class="special">></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"><</span><span class="identifier">Tp</span><span class="special">>::</span><span class="identifier">type</span></code>:
|
||||
</p>
|
||||
<pre class="programlisting"><span class="keyword">template</span><span class="special"><</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"><</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">tuple</span><span class="special"><>,</span> <span class="identifier">remove_cv_ref</span><span class="special"><</span><span class="identifier">Tp</span><span class="special">>...>></span>
|
||||
<span class="identifier">R</span> <span class="identifier">tuple_cat</span><span class="special">(</span> <span class="identifier">Tp</span> <span class="special">&&...</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"><</span><span class="identifier">mp_rename</span><span class="special"><</span><span class="identifier">remove_cv_ref</span><span class="special"><</span><span class="identifier">Tp</span><span class="special">>,</span> <span class="identifier">mp_list</span><span class="special">>...>;</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"><</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">tuple_element</span><span class="special"><</span><span class="number">0</span><span class="special">,</span>
|
||||
<span class="identifier">Tp</span><span class="special">>,</span>
|
||||
<span class="identifier">std</span><span class="special">::</span><span class="identifier">tuple_element</span><span class="special"><</span><span class="number">1</span><span class="special">,</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">tuple_element</span><span class="special"><</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">>></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"><</span><span class="identifier">Tp</span><span class="special">>::</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"><</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">></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"><</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">>;</span>
|
||||
<span class="keyword">template</span><span class="special"><</span><span class="keyword">class</span> <span class="identifier">T</span><span class="special">></span> <span class="keyword">using</span> <span class="identifier">from_tuple_like</span> <span class="special">=</span> <span class="identifier">mp_product</span><span class="special"><</span><span class="identifier">tuple_element</span><span class="special">,</span> <span class="identifier">mp_list</span><span class="special"><</span><span class="identifier">T</span><span class="special">>,</span> <span class="identifier">mp_iota</span><span class="special"><</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">tuple_size</span><span class="special"><</span><span class="identifier">T</span><span class="special">>>>;</span>
|
||||
</pre>
|
||||
<p>
|
||||
(<code class="computeroutput"><span class="identifier">mp_iota</span><span class="special"><</span><span class="identifier">N</span><span class="special">></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"><</span><span class="number">0</span><span class="special">></span></code>, <code class="computeroutput"><span class="identifier">mp_size_t</span><span class="special"><</span><span class="number">1</span><span class="special">></span></code>, ...,
|
||||
<code class="computeroutput"><span class="identifier">mp_size_t</span><span class="special"><</span><span class="identifier">N</span><span class="special">-</span><span class="number">1</span><span class="special">></span></code>.)
|
||||
</p>
|
||||
<p>
|
||||
Remember that <code class="computeroutput"><span class="identifier">mp_product</span><span class="special"><</span><span class="identifier">F</span><span class="special">,</span>
|
||||
<span class="identifier">L1</span><span class="special">,</span> <span class="identifier">L2</span><span class="special">></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"><</span><span class="identifier">N</span><span class="special">></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"><</span><span class="identifier">T</span><span class="special">></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"><</span><span class="identifier">T</span><span class="special">,</span> <span class="identifier">mp_size_t</span><span class="special"><</span><span class="number">0</span><span class="special">>></span></code>,
|
||||
<code class="computeroutput"><span class="identifier">tuple_element</span><span class="special"><</span><span class="identifier">T</span><span class="special">,</span> <span class="identifier">mp_size_t</span><span class="special"><</span><span class="number">1</span><span class="special">>></span></code>,
|
||||
..., <code class="computeroutput"><span class="identifier">tuple_element</span><span class="special"><</span><span class="identifier">T</span><span class="special">,</span> <span class="identifier">mp_size_t</span><span class="special"><</span><span class="identifier">N</span><span class="special">-</span><span class="number">1</span><span class="special">>></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"><</span><span class="keyword">class</span> <span class="identifier">T</span><span class="special">></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"><</span><span class="identifier">mp_bind_front</span><span class="special"><</span><span class="identifier">tuple_element</span><span class="special">,</span> <span class="identifier">T</span><span class="special">>,</span> <span class="identifier">mp_iota</span><span class="special"><</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">tuple_size</span><span class="special"><</span><span class="identifier">T</span><span class="special">>>>;</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"><</span><span class="keyword">class</span> <span class="identifier">L</span><span class="special">></span> <span class="keyword">using</span> <span class="identifier">F</span> <span class="special">=</span> <span class="identifier">mp_iota</span><span class="special"><</span><span class="identifier">mp_size</span><span class="special"><</span><span class="identifier">L</span><span class="special">>>;</span>
|
||||
|
||||
<span class="keyword">template</span><span class="special"><</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">></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"><</span><span class="identifier">Is</span><span class="special">...>,</span> <span class="identifier">mp_list</span><span class="special"><</span><span class="identifier">Ks</span><span class="special">...>,</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"><</span><span class="identifier">Ks</span><span class="special">::</span><span class="identifier">value</span><span class="special">>(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">get</span><span class="special"><</span><span class="identifier">Is</span><span class="special">::</span><span class="identifier">value</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">tp</span><span class="special">)))...</span> <span class="special">};</span>
|
||||
<span class="special">}</span>
|
||||
|
||||
<span class="keyword">template</span><span class="special"><</span><span class="keyword">class</span> <span class="identifier">T</span><span class="special">></span> <span class="keyword">using</span> <span class="identifier">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"><</span>
|
||||
<span class="keyword">typename</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">remove_reference</span><span class="special"><</span><span class="identifier">T</span><span class="special">>::</span><span class="identifier">type</span><span class="special">>::</span><span class="identifier">type</span><span class="special">;</span>
|
||||
|
||||
<span class="keyword">template</span><span class="special"><</span><span class="keyword">class</span> <span class="identifier">T</span><span class="special">,</span> <span class="keyword">class</span> <span class="identifier">I</span><span class="special">></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"><</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">>;</span>
|
||||
<span class="keyword">template</span><span class="special"><</span><span class="keyword">class</span> <span class="identifier">T</span><span class="special">></span> <span class="keyword">using</span> <span class="identifier">from_tuple_like</span> <span class="special">=</span> <span class="identifier">mp_product</span><span class="special"><</span><span class="identifier">tuple_element</span><span class="special">,</span> <span class="identifier">mp_list</span><span class="special"><</span><span class="identifier">T</span><span class="special">>,</span> <span class="identifier">mp_iota</span><span class="special"><</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">tuple_size</span><span class="special"><</span><span class="identifier">T</span><span class="special">>>>;</span>
|
||||
|
||||
<span class="keyword">template</span><span class="special"><</span><span class="keyword">class</span><span class="special">...</span> <span class="identifier">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"><</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">tuple</span><span class="special"><>,</span> <span class="identifier">from_tuple_like</span><span class="special"><</span><span class="identifier">remove_cv_ref</span><span class="special"><</span><span class="identifier">Tp</span><span class="special">>>...>></span>
|
||||
<span class="identifier">R</span> <span class="identifier">tuple_cat</span><span class="special">(</span> <span class="identifier">Tp</span> <span class="special">&&...</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"><</span><span class="identifier">from_tuple_like</span><span class="special"><</span><span class="identifier">remove_cv_ref</span><span class="special"><</span><span class="identifier">Tp</span><span class="special">>>...>;</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"><</span><span class="identifier">N</span><span class="special">>;</span>
|
||||
|
||||
<span class="keyword">using</span> <span class="identifier">list3</span> <span class="special">=</span> <span class="identifier">mp_transform</span><span class="special"><</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">>;</span>
|
||||
|
||||
<span class="keyword">using</span> <span class="identifier">inner</span> <span class="special">=</span> <span class="identifier">mp_apply</span><span class="special"><</span><span class="identifier">mp_append</span><span class="special">,</span> <span class="identifier">list3</span><span class="special">>;</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"><</span><span class="identifier">F</span><span class="special">,</span> <span class="identifier">list1</span><span class="special">>;</span>
|
||||
|
||||
<span class="keyword">using</span> <span class="identifier">outer</span> <span class="special">=</span> <span class="identifier">mp_apply</span><span class="special"><</span><span class="identifier">mp_append</span><span class="special">,</span> <span class="identifier">list4</span><span class="special">>;</span>
|
||||
|
||||
<span class="comment">//</span>
|
||||
|
||||
<span class="keyword">return</span> <span class="identifier">tuple_cat_</span><span class="special"><</span><span class="identifier">R</span><span class="special">>(</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"><</span><span class="identifier">Tp</span><span class="special">>(</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"><</span><span class="identifier">L</span><span class="special"><</span><span class="identifier">T</span><span class="special">...>></span></code>
|
||||
is an alias for <code class="computeroutput"><span class="identifier">mp_size_t</span><span class="special"><</span><span class="keyword">sizeof</span><span class="special">...(</span><span class="identifier">T</span><span class="special">)></span></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"><>;</span>
|
||||
<span class="keyword">using</span> <span class="identifier">R1</span> <span class="special">=</span> <span class="identifier">mp_size</span><span class="special"><</span><span class="identifier">L1</span><span class="special">>;</span> <span class="comment">// mp_size_t<0></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"><</span><span class="keyword">int</span><span class="special">,</span> <span class="keyword">int</span><span class="special">>;</span>
|
||||
<span class="keyword">using</span> <span class="identifier">R2</span> <span class="special">=</span> <span class="identifier">mp_size</span><span class="special"><</span><span class="identifier">L2</span><span class="special">>;</span> <span class="comment">// mp_size_t<2></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"><</span><span class="keyword">float</span><span class="special">>;</span>
|
||||
<span class="keyword">using</span> <span class="identifier">R3</span> <span class="special">=</span> <span class="identifier">mp_size</span><span class="special"><</span><span class="identifier">L3</span><span class="special">>;</span> <span class="comment">// mp_size_t<1></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"><</span><span class="identifier">L</span><span class="special"><</span><span class="identifier">T1</span><span class="special">,</span> <span class="identifier">T</span><span class="special">...>></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"><</span><span class="keyword">int</span><span class="special">,</span> <span class="keyword">float</span><span class="special">>;</span>
|
||||
<span class="keyword">using</span> <span class="identifier">R1</span> <span class="special">=</span> <span class="identifier">mp_front</span><span class="special"><</span><span class="identifier">L1</span><span class="special">>;</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"><</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">>;</span>
|
||||
<span class="keyword">using</span> <span class="identifier">R2</span> <span class="special">=</span> <span class="identifier">mp_front</span><span class="special"><</span><span class="identifier">L2</span><span class="special">>;</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"><</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">]>;</span>
|
||||
<span class="keyword">using</span> <span class="identifier">R3</span> <span class="special">=</span> <span class="identifier">mp_front</span><span class="special"><</span><span class="identifier">L3</span><span class="special">>;</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"><</span><span class="identifier">L</span><span class="special"><</span><span class="identifier">T1</span><span class="special">,</span> <span class="identifier">T</span><span class="special">...>></span></code>
|
||||
is an alias for <code class="computeroutput"><span class="identifier">L</span><span class="special"><</span><span class="identifier">T</span><span class="special">...></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"><</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">>;</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"><</span><span class="identifier">L1</span><span class="special">>;</span> <span class="comment">// std::tuple<double, 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"><</span><span class="keyword">void</span><span class="special">>;</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"><</span><span class="identifier">L2</span><span class="special">>;</span> <span class="comment">// mp_list<></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"><</span><span class="identifier">L</span><span class="special"><</span><span class="identifier">T1</span><span class="special">,</span> <span class="identifier">T2</span><span class="special">,</span> <span class="identifier">T</span><span class="special">...>></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"><</span><span class="keyword">int</span><span class="special">,</span> <span class="keyword">float</span><span class="special">>;</span>
|
||||
<span class="keyword">using</span> <span class="identifier">R1</span> <span class="special">=</span> <span class="identifier">mp_second</span><span class="special"><</span><span class="identifier">L1</span><span class="special">>;</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"><</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">>;</span>
|
||||
<span class="keyword">using</span> <span class="identifier">R2</span> <span class="special">=</span> <span class="identifier">mp_second</span><span class="special"><</span><span class="identifier">L2</span><span class="special">>;</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"><</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">]>;</span>
|
||||
<span class="keyword">using</span> <span class="identifier">R3</span> <span class="special">=</span> <span class="identifier">mp_second</span><span class="special"><</span><span class="identifier">L3</span><span class="special">>;</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"><</span><span class="identifier">L</span><span class="special"><</span><span class="identifier">T1</span><span class="special">,</span> <span class="identifier">T2</span><span class="special">,</span> <span class="identifier">T3</span><span class="special">,</span> <span class="identifier">T</span><span class="special">...>></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"><</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">>;</span>
|
||||
<span class="keyword">using</span> <span class="identifier">R1</span> <span class="special">=</span> <span class="identifier">mp_third</span><span class="special"><</span><span class="identifier">L1</span><span class="special">>;</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"><</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">]>;</span>
|
||||
<span class="keyword">using</span> <span class="identifier">R2</span> <span class="special">=</span> <span class="identifier">mp_third</span><span class="special"><</span><span class="identifier">L2</span><span class="special">>;</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"><</span><span class="identifier">L</span><span class="special"><</span><span class="identifier">U</span><span class="special">...>,</span> <span class="identifier">T</span><span class="special">...></span></code> is an alias for <code class="computeroutput"><span class="identifier">L</span><span class="special"><</span><span class="identifier">T</span><span class="special">...,</span> <span class="identifier">U</span><span class="special">...></span></code>.
|
||||
</p>
|
||||
<pre class="programlisting"><span class="keyword">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"><</span><span class="keyword">double</span><span class="special">,</span> <span class="keyword">long</span> <span class="keyword">double</span><span class="special">>;</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"><</span><span class="identifier">L1</span><span class="special">,</span> <span class="keyword">float</span><span class="special">>;</span> <span class="comment">// std::tuple<float, double, 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"><</span><span class="keyword">void</span><span class="special">>;</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"><</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">]>;</span> <span class="comment">// mp_list<char[1], char[2], void></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"><</span><span class="identifier">L</span><span class="special"><</span><span class="identifier">U</span><span class="special">...>,</span> <span class="identifier">T</span><span class="special">...></span></code>
|
||||
is an alias for <code class="computeroutput"><span class="identifier">L</span><span class="special"><</span><span class="identifier">U</span><span class="special">...,</span> <span class="identifier">T</span><span class="special">...></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"><</span><span class="keyword">double</span><span class="special">,</span> <span class="keyword">long</span> <span class="keyword">double</span><span class="special">>;</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"><</span><span class="identifier">L1</span><span class="special">,</span> <span class="keyword">float</span><span class="special">>;</span> <span class="comment">// std::tuple<double, long double, float></span>
|
||||
|
||||
<span class="keyword">using</span> <span class="identifier">L2</span> <span class="special">=</span> <span class="identifier">mp_list</span><span class="special"><</span><span class="keyword">void</span><span class="special">>;</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"><</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">]>;</span> <span class="comment">// mp_list<void, char[1], char[2]></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"><</span><span class="identifier">L</span><span class="special"><</span><span class="identifier">T</span><span class="special">...>,</span> <span class="identifier">Y</span><span class="special">></span></code>
|
||||
is an alias for <code class="computeroutput"><span class="identifier">Y</span><span class="special"><</span><span class="identifier">T</span><span class="special">...></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"><</span><span class="keyword">double</span><span class="special">,</span> <span class="keyword">long</span> <span class="keyword">double</span><span class="special">>;</span>
|
||||
<span class="keyword">using</span> <span class="identifier">R1</span> <span class="special">=</span> <span class="identifier">mp_rename</span><span class="special"><</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">>;</span> <span class="comment">// std::tuple<double, long double></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"><</span><span class="keyword">void</span><span class="special">>;</span>
|
||||
<span class="keyword">using</span> <span class="identifier">R2</span> <span class="special">=</span> <span class="identifier">mp_rename</span><span class="special"><</span><span class="identifier">L2</span><span class="special">,</span> <span class="identifier">mp_list</span><span class="special">>;</span> <span class="comment">// mp_list<void></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"><</span><span class="keyword">double</span><span class="special">,</span> <span class="keyword">long</span> <span class="keyword">double</span><span class="special">>;</span>
|
||||
<span class="keyword">using</span> <span class="identifier">R1</span> <span class="special">=</span> <span class="identifier">mp_apply</span><span class="special"><</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">is_same</span><span class="special">,</span> <span class="identifier">L1</span><span class="special">>;</span> <span class="comment">// std::is_same<double, long double></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"><</span><span class="keyword">double</span><span class="special">,</span> <span class="keyword">long</span> <span class="keyword">double</span><span class="special">>;</span>
|
||||
<span class="keyword">using</span> <span class="identifier">L2</span> <span class="special">=</span> <span class="identifier">mp_list</span><span class="special"><</span><span class="keyword">int</span><span class="special">,</span> <span class="keyword">long</span><span class="special">>;</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"><</span><span class="identifier">mp_bind_front</span><span class="special"><</span><span class="identifier">mp_push_back</span><span class="special">,</span> <span class="identifier">L1</span><span class="special">>,</span> <span class="identifier">L2</span><span class="special">>;</span> <span class="comment">// std::tuple<double, long double, int, long></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"><</span><span class="identifier">Tn</span><span class="special">...>></span></code>
|
||||
is an alias for <code class="computeroutput"><span class="identifier">L1</span><span class="special"><</span><span class="identifier">T1</span><span class="special">...,</span> <span class="identifier">T2</span><span class="special">...,</span> <span class="special">...,</span> <span class="identifier">Tn</span><span class="special">...></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"><</span><span class="keyword">double</span><span class="special">,</span> <span class="keyword">long</span> <span class="keyword">double</span><span class="special">>;</span>
|
||||
<span class="keyword">using</span> <span class="identifier">L2</span> <span class="special">=</span> <span class="identifier">mp_list</span><span class="special"><</span><span class="keyword">int</span><span class="special">>;</span>
|
||||
<span class="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"><</span><span class="keyword">short</span><span class="special">,</span> <span class="keyword">long</span><span class="special">>;</span>
|
||||
<span class="keyword">using</span> <span class="identifier">L4</span> <span class="special">=</span> <span class="identifier">mp_list</span><span class="special"><>;</span>
|
||||
|
||||
<span class="keyword">using</span> <span class="identifier">R1</span> <span class="special">=</span> <span class="identifier">mp_append</span><span class="special"><</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">>;</span> <span class="comment">// std::tuple<double, long double, int, short, long></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">></span></code>
|
||||
is an alias for <code class="computeroutput"><span class="identifier">L</span><span class="special"><</span><span class="identifier">T</span><span class="special">,</span> <span class="identifier">U</span><span class="special">...></span></code>.
|
||||
</p>
|
||||
<pre class="programlisting"><span class="keyword">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"><</span><span class="keyword">int</span><span class="special">,</span> <span class="keyword">float</span><span class="special">>;</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"><</span><span class="identifier">L1</span><span class="special">,</span> <span class="keyword">void</span><span class="special">>;</span> <span class="comment">// std::pair<void, 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"><</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">>;</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"><</span><span class="identifier">L2</span><span class="special">,</span> <span class="keyword">void</span><span class="special">>;</span> <span class="comment">// std::tuple<void, double, long 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"><</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">]>;</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"><</span><span class="identifier">L3</span><span class="special">,</span> <span class="keyword">void</span><span class="special">>;</span> <span class="comment">// mp_list<void, char[2], char[3], char[4]>;</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">></span></code>
|
||||
is an alias for <code class="computeroutput"><span class="identifier">L</span><span class="special"><</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">...></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"><</span><span class="keyword">int</span><span class="special">,</span> <span class="keyword">float</span><span class="special">>;</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"><</span><span class="identifier">L1</span><span class="special">,</span> <span class="keyword">void</span><span class="special">>;</span> <span class="comment">// std::pair<int, void></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"><</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">>;</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"><</span><span class="identifier">L2</span><span class="special">,</span> <span class="keyword">void</span><span class="special">>;</span> <span class="comment">// std::tuple<float, void, long 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"><</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">]>;</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"><</span><span class="identifier">L3</span><span class="special">,</span> <span class="keyword">void</span><span class="special">>;</span> <span class="comment">// mp_list<char[1], void, char[3], char[4]>;</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">></span></code>
|
||||
is an alias for <code class="computeroutput"><span class="identifier">L</span><span class="special"><</span><span class="identifier">U1</span><span class="special">,</span> <span class="identifier">U2</span><span class="special">,</span> <span class="identifier">T</span><span class="special">,</span> <span class="identifier">U</span><span class="special">...></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"><</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">>;</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"><</span><span class="identifier">L1</span><span class="special">,</span> <span class="keyword">void</span><span class="special">>;</span> <span class="comment">// std::tuple<float, double, void></span>
|
||||
|
||||
<span class="keyword">using</span> <span class="identifier">L2</span> <span class="special">=</span> <span class="identifier">mp_list</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">],</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">]>;</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"><</span><span class="identifier">L2</span><span class="special">,</span> <span class="keyword">void</span><span class="special">>;</span> <span class="comment">// mp_list<char[1], char[2], void, char[4]>;</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>
|
||||
|
@@ -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]
|
||||
|
@@ -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]
|
||||
|
Reference in New Issue
Block a user