1
0
forked from boostorg/mp11

Merge branch 'develop'

This commit is contained in:
Peter Dimov
2017-05-19 16:40:45 +03:00
12 changed files with 481 additions and 98 deletions

View File

@@ -38,6 +38,8 @@
<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.writing_common_type_specializati">Writing
<code class="computeroutput"><span class="identifier">common_type</span></code> specializations</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>
@@ -84,13 +86,15 @@
<dt><span class="section"><a href="mp11.html#mp11.reference.utility.mp_identity_t"><code class="computeroutput"><span class="identifier">mp_identity</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">&gt;</span></code></a></span></dt>
<dt><span class="section"><a href="mp11.html#mp11.reference.utility.mp_identity_t_t"><code class="computeroutput"><span class="identifier">mp_identity_t</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">&gt;</span></code></a></span></dt>
<dt><span class="section"><a href="mp11.html#mp11.reference.utility.mp_inherit_t"><code class="computeroutput"><span class="identifier">mp_inherit</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">...&gt;</span></code></a></span></dt>
<dt><span class="section"><a href="mp11.html#mp11.reference.utility.mp_if_c_b_t_e"><code class="computeroutput"><span class="identifier">mp_if_c</span><span class="special">&lt;</span><span class="identifier">B</span><span class="special">,</span> <span class="identifier">T</span><span class="special">,</span> <span class="identifier">E</span><span class="special">&gt;</span></code></a></span></dt>
<dt><span class="section"><a href="mp11.html#mp11.reference.utility.mp_if_c_c_t_e"><code class="computeroutput"><span class="identifier">mp_if_c</span><span class="special">&lt;</span><span class="identifier">C</span><span class="special">,</span> <span class="identifier">T</span><span class="special">,</span> <span class="identifier">E</span><span class="special">...&gt;</span></code></a></span></dt>
<dt><span class="section"><a href="mp11.html#mp11.reference.utility.mp_if_c_t_e"><code class="computeroutput"><span class="identifier">mp_if</span><span class="special">&lt;</span><span class="identifier">C</span><span class="special">,</span>
<span class="identifier">T</span><span class="special">,</span> <span class="identifier">E</span><span class="special">&gt;</span></code></a></span></dt>
<dt><span class="section"><a href="mp11.html#mp11.reference.utility.mp_eval_if_c_b_t_f_u"><code class="computeroutput"><span class="identifier">mp_eval_if_c</span><span class="special">&lt;</span><span class="identifier">B</span><span class="special">,</span> <span class="identifier">T</span><span class="special">,</span> <span class="identifier">F</span><span class="special">,</span>
<span class="identifier">T</span><span class="special">,</span> <span class="identifier">E</span><span class="special">...&gt;</span></code></a></span></dt>
<dt><span class="section"><a href="mp11.html#mp11.reference.utility.mp_eval_if_c_c_t_f_u"><code class="computeroutput"><span class="identifier">mp_eval_if_c</span><span class="special">&lt;</span><span class="identifier">C</span><span class="special">,</span> <span class="identifier">T</span><span class="special">,</span> <span class="identifier">F</span><span class="special">,</span>
<span class="identifier">U</span><span class="special">...&gt;</span></code></a></span></dt>
<dt><span class="section"><a href="mp11.html#mp11.reference.utility.mp_eval_if_c_t_f_u"><code class="computeroutput"><span class="identifier">mp_eval_if</span><span class="special">&lt;</span><span class="identifier">C</span><span class="special">,</span> <span class="identifier">T</span><span class="special">,</span> <span class="identifier">F</span><span class="special">,</span>
<span class="identifier">U</span><span class="special">...&gt;</span></code></a></span></dt>
<dt><span class="section"><a href="mp11.html#mp11.reference.utility.mp_eval_if_q_c_t_q_u"><code class="computeroutput"><span class="identifier">mp_eval_if_q</span><span class="special">&lt;</span><span class="identifier">C</span><span class="special">,</span> <span class="identifier">T</span><span class="special">,</span> <span class="identifier">Q</span><span class="special">,</span>
<span class="identifier">U</span><span class="special">...&gt;</span></code></a></span></dt>
<dt><span class="section"><a href="mp11.html#mp11.reference.utility.mp_valid_f_t"><code class="computeroutput"><span class="identifier">mp_valid</span><span class="special">&lt;</span><span class="identifier">F</span><span class="special">,</span> <span class="identifier">T</span><span class="special">...&gt;</span></code></a></span></dt>
<dt><span class="section"><a href="mp11.html#mp11.reference.utility.mp_defer_f_t"><code class="computeroutput"><span class="identifier">mp_defer</span><span class="special">&lt;</span><span class="identifier">F</span><span class="special">,</span> <span class="identifier">T</span><span class="special">...&gt;</span></code></a></span></dt>
<dt><span class="section"><a href="mp11.html#mp11.reference.utility.mp_quote_f"><code class="computeroutput"><span class="identifier">mp_quote</span><span class="special">&lt;</span><span class="identifier">F</span><span class="special">&gt;</span></code></a></span></dt>
@@ -166,6 +170,7 @@
<dt><span class="section"><a href="mp11.html#mp11.reference.function.mp_all_t"><code class="computeroutput"><span class="identifier">mp_all</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">...&gt;</span></code></a></span></dt>
<dt><span class="section"><a href="mp11.html#mp11.reference.function.mp_or_t"><code class="computeroutput"><span class="identifier">mp_or</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">...&gt;</span></code></a></span></dt>
<dt><span class="section"><a href="mp11.html#mp11.reference.function.mp_any_t"><code class="computeroutput"><span class="identifier">mp_any</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">...&gt;</span></code></a></span></dt>
<dt><span class="section"><a href="mp11.html#mp11.reference.function.mp_same_t"><code class="computeroutput"><span class="identifier">mp_same</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">...&gt;</span></code></a></span></dt>
</dl></dd>
<dt><span class="section"><a href="mp11.html#mp11.reference.bind">Bind, <code class="computeroutput"><span class="special">&lt;</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">mp11</span><span class="special">/</span><span class="identifier">bind</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span></code></a></span></dt>
<dd><dl>
@@ -400,6 +405,102 @@
</div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="mp11.examples.writing_common_type_specializati"></a><a class="link" href="mp11.html#mp11.examples.writing_common_type_specializati" title="Writing common_type specializations">Writing
<code class="computeroutput"><span class="identifier">common_type</span></code> specializations</a>
</h3></div></div></div>
<p>
The standard trait <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">common_type</span></code>, used to obtain a type to which
all of its arguments can convert without unnecessary loss of precision, can
be user-specialized when its default implementation (based on the ternary
<code class="computeroutput"><span class="special">?:</span></code> operator) is unsuitable.
</p>
<p>
Let's write a <code class="computeroutput"><span class="identifier">common_type</span></code>
specialization for two <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">tuple</span></code>
arguments. For that, we need a metafunction that applies <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">common_type</span></code>
to each pair of elements and gathers the results into a tuple:
</p>
<pre class="programlisting"><span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">class</span> <span class="identifier">Tp1</span><span class="special">,</span> <span class="keyword">class</span> <span class="identifier">Tp2</span><span class="special">&gt;</span> <span class="keyword">using</span> <span class="identifier">common_tuple</span> <span class="special">=</span> <span class="identifier">mp_transform</span><span class="special">&lt;</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">common_type_t</span><span class="special">,</span> <span class="identifier">Tp1</span><span class="special">,</span> <span class="identifier">Tp2</span><span class="special">&gt;;</span>
</pre>
<p>
then specialize <code class="computeroutput"><span class="identifier">common_type</span></code>
to use it:
</p>
<pre class="programlisting"><span class="keyword">namespace</span> <span class="identifier">std</span>
<span class="special">{</span>
<span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">class</span><span class="special">...</span> <span class="identifier">T1</span><span class="special">,</span> <span class="keyword">class</span><span class="special">...</span> <span class="identifier">T2</span><span class="special">&gt;</span> <span class="keyword">struct</span> <span class="identifier">common_type</span><span class="special">&lt;</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">tuple</span><span class="special">&lt;</span><span class="identifier">T1</span><span class="special">...&gt;,</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">tuple</span><span class="special">&lt;</span><span class="identifier">T2</span><span class="special">...&gt;&gt;:</span> <span class="identifier">mp_defer</span><span class="special">&lt;</span><span class="identifier">common_tuple</span><span class="special">,</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">tuple</span><span class="special">&lt;</span><span class="identifier">T1</span><span class="special">...&gt;,</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">tuple</span><span class="special">&lt;</span><span class="identifier">T2</span><span class="special">...&gt;&gt;</span>
<span class="special">{</span>
<span class="special">};</span>
<span class="special">}</span> <span class="comment">// std</span>
</pre>
<p>
(There is no need to specialize <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">common_type</span></code>
for more than two arguments - it takes care of synthesizing the appropriate
semantics from the binary case.)
</p>
<p>
The subtlety here is the use of <code class="computeroutput"><span class="identifier">mp_defer</span></code>.
We could have defined a nested <code class="computeroutput"><span class="identifier">type</span></code>
to <code class="computeroutput"><span class="identifier">common_tuple</span><span class="special">&lt;</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">tuple</span><span class="special">&lt;</span><span class="identifier">T1</span><span class="special">...&gt;,</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">tuple</span><span class="special">&lt;</span><span class="identifier">T2</span><span class="special">...&gt;&gt;</span></code>, and it would still have worked
in all valid cases. By letting <code class="computeroutput"><span class="identifier">mp_defer</span></code>
define <code class="computeroutput"><span class="identifier">type</span></code>, though, we make
our specialization <span class="emphasis"><em>SFINAE-friendly</em></span>.
</p>
<p>
That is, when our <code class="computeroutput"><span class="identifier">common_tuple</span></code>
causes a substitution failure instead of a hard error, <code class="computeroutput"><span class="identifier">mp_defer</span></code>
will not define a nested <code class="computeroutput"><span class="identifier">type</span></code>,
and <code class="computeroutput"><span class="identifier">common_type_t</span></code>, which
is defined as <code class="computeroutput"><span class="keyword">typename</span> <span class="identifier">common_type</span><span class="special">&lt;...&gt;::</span><span class="identifier">type</span></code>,
will also cause a substitution failure.
</p>
<p>
As another example, consider the hypothetical type <code class="computeroutput"><span class="identifier">expected</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">,</span>
<span class="identifier">E</span><span class="special">...&gt;</span></code>
that represents either a successful return with a value of <code class="computeroutput"><span class="identifier">T</span></code>, or an unsucessful return with an error
code of some type in the list <code class="computeroutput"><span class="identifier">E</span><span class="special">...</span></code>. The common type of <code class="computeroutput"><span class="identifier">expected</span><span class="special">&lt;</span><span class="identifier">T1</span><span class="special">,</span> <span class="identifier">E1</span><span class="special">,</span>
<span class="identifier">E2</span><span class="special">,</span> <span class="identifier">E3</span><span class="special">&gt;</span></code>
and <code class="computeroutput"><span class="identifier">expected</span><span class="special">&lt;</span><span class="identifier">T2</span><span class="special">,</span> <span class="identifier">E1</span><span class="special">,</span> <span class="identifier">E4</span><span class="special">,</span>
<span class="identifier">E5</span><span class="special">&gt;</span></code>
is <code class="computeroutput"><span class="identifier">expected</span><span class="special">&lt;</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">common_type_t</span><span class="special">&lt;</span><span class="identifier">T1</span><span class="special">,</span> <span class="identifier">T2</span><span class="special">&gt;,</span>
<span class="identifier">E1</span><span class="special">,</span> <span class="identifier">E2</span><span class="special">,</span> <span class="identifier">E3</span><span class="special">,</span> <span class="identifier">E4</span><span class="special">,</span>
<span class="identifier">E5</span><span class="special">&gt;</span></code>.
That is, the possible return values are combined into their common type,
and we take the union of the set of error types.
</p>
<p>
Therefore,
</p>
<pre class="programlisting"><span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">class</span> <span class="identifier">T1</span><span class="special">,</span> <span class="keyword">class</span> <span class="identifier">E1</span><span class="special">,</span> <span class="keyword">class</span> <span class="identifier">T2</span><span class="special">,</span> <span class="keyword">class</span> <span class="identifier">E2</span><span class="special">&gt;</span> <span class="keyword">using</span> <span class="identifier">common_expected</span> <span class="special">=</span> <span class="identifier">mp_rename</span><span class="special">&lt;</span><span class="identifier">mp_push_front</span><span class="special">&lt;</span><span class="identifier">mp_unique</span><span class="special">&lt;</span><span class="identifier">mp_append</span><span class="special">&lt;</span><span class="identifier">E1</span><span class="special">,</span> <span class="identifier">E2</span><span class="special">&gt;&gt;,</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">common_type_t</span><span class="special">&lt;</span><span class="identifier">T1</span><span class="special">,</span> <span class="identifier">T2</span><span class="special">&gt;&gt;,</span> <span class="identifier">expected</span><span class="special">&gt;;</span>
<span class="keyword">namespace</span> <span class="identifier">std</span>
<span class="special">{</span>
<span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">class</span> <span class="identifier">T1</span><span class="special">,</span> <span class="keyword">class</span><span class="special">...</span> <span class="identifier">E1</span><span class="special">,</span> <span class="keyword">class</span> <span class="identifier">T2</span><span class="special">,</span> <span class="keyword">class</span><span class="special">...</span> <span class="identifier">E2</span><span class="special">&gt;</span> <span class="keyword">struct</span> <span class="identifier">common_type</span><span class="special">&lt;</span><span class="identifier">expected</span><span class="special">&lt;</span><span class="identifier">T1</span><span class="special">,</span> <span class="identifier">E1</span><span class="special">...&gt;,</span> <span class="identifier">expected</span><span class="special">&lt;</span><span class="identifier">T2</span><span class="special">,</span> <span class="identifier">E2</span><span class="special">...&gt;&gt;:</span> <span class="identifier">mp_defer</span><span class="special">&lt;</span><span class="identifier">common_expected</span><span class="special">,</span> <span class="identifier">T1</span><span class="special">,</span> <span class="identifier">mp_list</span><span class="special">&lt;</span><span class="identifier">E1</span><span class="special">...&gt;,</span> <span class="identifier">T2</span><span class="special">,</span> <span class="identifier">mp_list</span><span class="special">&lt;</span><span class="identifier">E2</span><span class="special">...&gt;&gt;</span>
<span class="special">{</span>
<span class="special">};</span>
<span class="special">}</span> <span class="comment">// std</span>
</pre>
<p>
Here we've taken a different tack; instead of passing the <code class="computeroutput"><span class="identifier">expected</span></code>
types to <code class="computeroutput"><span class="identifier">common_expected</span></code>,
we're passing the <code class="computeroutput"><span class="identifier">T</span></code> types
and lists of the <code class="computeroutput"><span class="identifier">E</span></code> types.
This makes our job easier. <code class="computeroutput"><span class="identifier">mp_unique</span><span class="special">&lt;</span><span class="identifier">mp_append</span><span class="special">&lt;</span><span class="identifier">E1</span><span class="special">,</span> <span class="identifier">E2</span><span class="special">&gt;&gt;</span></code>
gives us the concatenation of <code class="computeroutput"><span class="identifier">E1</span></code>
and <code class="computeroutput"><span class="identifier">E2</span></code> with the duplicates
removed; we then add <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">common_type_t</span><span class="special">&lt;</span><span class="identifier">T1</span><span class="special">,</span> <span class="identifier">T2</span><span class="special">&gt;</span></code>
to the front via <code class="computeroutput"><span class="identifier">mp_push_front</span></code>;
and finally, we <code class="computeroutput"><span class="identifier">mp_rename</span></code>
the resultant <code class="computeroutput"><span class="identifier">mp_list</span></code> to
<code class="computeroutput"><span class="identifier">expected</span></code>.
</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>
@@ -473,7 +574,7 @@
<pre class="programlisting"><span class="identifier">std</span><span class="special">::</span><span class="identifier">array</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">,</span> <span class="number">2</span><span class="special">&gt;</span> <span class="identifier">t1</span><span class="special">{</span> <span class="number">1</span><span class="special">,</span> <span class="number">2</span> <span class="special">};</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">array</span><span class="special">&lt;</span><span class="keyword">float</span><span class="special">,</span> <span class="number">3</span><span class="special">&gt;</span> <span class="identifier">t2</span><span class="special">{</span> <span class="number">3.0f</span><span class="special">,</span> <span class="number">4.0f</span><span class="special">,</span> <span class="number">5.0f</span> <span class="special">};</span>
<span class="keyword">auto</span> <span class="identifier">result</span> <span class="special">=</span> <span class="special">::</span><span class="identifier">tuple_cat</span><span class="special">(</span> <span class="identifier">t1</span><span class="special">,</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">move</span><span class="special">(</span> <span class="identifier">t2</span> <span class="special">)</span> <span class="special">);</span>
<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>
Let's fix these one by one. Support for move-only types is easy, if one knows
@@ -541,11 +642,11 @@
<p>
What we need is, given a tuple-like type <code class="computeroutput"><span class="identifier">Tp</span></code>,
to obtain <code class="computeroutput"><span class="identifier">mp_list</span><span class="special">&lt;</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">tuple_element</span><span class="special">&lt;</span><span class="number">0</span><span class="special">,</span>
<span class="identifier">Tp</span><span class="special">&gt;,</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">tuple_element</span><span class="special">&lt;</span><span class="number">1</span><span class="special">,</span> <span class="identifier">Tp</span><span class="special">&gt;,</span> <span class="special">...,</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">tuple_element</span><span class="special">&lt;</span><span class="identifier">N</span><span class="special">-</span><span class="number">1</span><span class="special">,</span> <span class="identifier">Tp</span><span class="special">&gt;&gt;</span></code>, where <code class="computeroutput"><span class="identifier">N</span></code>
<span class="identifier">Tp</span><span class="special">&gt;::</span><span class="identifier">type</span><span class="special">,</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">tuple_element</span><span class="special">&lt;</span><span class="number">1</span><span class="special">,</span>
<span class="identifier">Tp</span><span class="special">&gt;::</span><span class="identifier">type</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">&lt;</span><span class="identifier">N</span><span class="special">-</span><span class="number">1</span><span class="special">,</span> <span class="identifier">Tp</span><span class="special">&gt;::</span><span class="identifier">type</span><span class="special">&gt;</span></code>, where <code class="computeroutput"><span class="identifier">N</span></code>
is <code class="computeroutput"><span class="identifier">tuple_size</span><span class="special">&lt;</span><span class="identifier">Tp</span><span class="special">&gt;::</span><span class="identifier">value</span></code>. Here's one way to do it:
</p>
<pre class="programlisting"><span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">class</span> <span class="identifier">T</span><span class="special">,</span> <span class="keyword">class</span> <span class="identifier">I</span><span class="special">&gt;</span> <span class="keyword">using</span> <span class="identifier">tuple_element</span> <span class="special">=</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">tuple_element_t</span><span class="special">&lt;</span><span class="identifier">I</span><span class="special">::</span><span class="identifier">value</span><span class="special">,</span> <span class="identifier">T</span><span class="special">&gt;;</span>
<pre class="programlisting"><span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">class</span> <span class="identifier">T</span><span class="special">,</span> <span class="keyword">class</span> <span class="identifier">I</span><span class="special">&gt;</span> <span class="keyword">using</span> <span class="identifier">tuple_element</span> <span class="special">=</span> <span class="keyword">typename</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">tuple_element</span><span class="special">&lt;</span><span class="identifier">I</span><span class="special">::</span><span class="identifier">value</span><span class="special">,</span> <span class="identifier">T</span><span class="special">&gt;::</span><span class="identifier">type</span><span class="special">;</span>
<span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">class</span> <span class="identifier">T</span><span class="special">&gt;</span> <span class="keyword">using</span> <span class="identifier">from_tuple_like</span> <span class="special">=</span> <span class="identifier">mp_product</span><span class="special">&lt;</span><span class="identifier">tuple_element</span><span class="special">,</span> <span class="identifier">mp_list</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">&gt;,</span> <span class="identifier">mp_iota</span><span class="special">&lt;</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">tuple_size</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">&gt;&gt;&gt;;</span>
</pre>
<p>
@@ -590,7 +691,7 @@
<span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">class</span> <span class="identifier">T</span><span class="special">&gt;</span> <span class="keyword">using</span> <span class="identifier">remove_cv_ref</span> <span class="special">=</span> <span class="keyword">typename</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">remove_cv</span><span class="special">&lt;</span>
<span class="keyword">typename</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">remove_reference</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">&gt;::</span><span class="identifier">type</span><span class="special">&gt;::</span><span class="identifier">type</span><span class="special">;</span>
<span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">class</span> <span class="identifier">T</span><span class="special">,</span> <span class="keyword">class</span> <span class="identifier">I</span><span class="special">&gt;</span> <span class="keyword">using</span> <span class="identifier">tuple_element</span> <span class="special">=</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">tuple_element_t</span><span class="special">&lt;</span><span class="identifier">I</span><span class="special">::</span><span class="identifier">value</span><span class="special">,</span> <span class="identifier">T</span><span class="special">&gt;;</span>
<span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">class</span> <span class="identifier">T</span><span class="special">,</span> <span class="keyword">class</span> <span class="identifier">I</span><span class="special">&gt;</span> <span class="keyword">using</span> <span class="identifier">tuple_element</span> <span class="special">=</span> <span class="keyword">typename</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">tuple_element</span><span class="special">&lt;</span><span class="identifier">I</span><span class="special">::</span><span class="identifier">value</span><span class="special">,</span> <span class="identifier">T</span><span class="special">&gt;::</span><span class="identifier">type</span><span class="special">;</span>
<span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">class</span> <span class="identifier">T</span><span class="special">&gt;</span> <span class="keyword">using</span> <span class="identifier">from_tuple_like</span> <span class="special">=</span> <span class="identifier">mp_product</span><span class="special">&lt;</span><span class="identifier">tuple_element</span><span class="special">,</span> <span class="identifier">mp_list</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">&gt;,</span> <span class="identifier">mp_iota</span><span class="special">&lt;</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">tuple_size</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">&gt;&gt;&gt;;</span>
<span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">class</span><span class="special">...</span> <span class="identifier">Tp</span><span class="special">,</span>
@@ -1209,43 +1310,45 @@
</div>
<div class="section">
<div class="titlepage"><div><div><h4 class="title">
<a name="mp11.reference.utility.mp_if_c_b_t_e"></a><a class="link" href="mp11.html#mp11.reference.utility.mp_if_c_b_t_e" title="mp_if_c&lt;B, T, E&gt;"><code class="computeroutput"><span class="identifier">mp_if_c</span><span class="special">&lt;</span><span class="identifier">B</span><span class="special">,</span> <span class="identifier">T</span><span class="special">,</span> <span class="identifier">E</span><span class="special">&gt;</span></code></a>
<a name="mp11.reference.utility.mp_if_c_c_t_e"></a><a class="link" href="mp11.html#mp11.reference.utility.mp_if_c_c_t_e" title="mp_if_c&lt;C, T, E...&gt;"><code class="computeroutput"><span class="identifier">mp_if_c</span><span class="special">&lt;</span><span class="identifier">C</span><span class="special">,</span> <span class="identifier">T</span><span class="special">,</span> <span class="identifier">E</span><span class="special">...&gt;</span></code></a>
</h4></div></div></div>
<pre class="programlisting"><span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">bool</span> <span class="identifier">C</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">E</span><span class="special">&gt;</span> <span class="keyword">using</span> <span class="identifier">mp_if_c</span> <span class="special">=</span> <span class="comment">/*...*/</span><span class="special">;</span>
<pre class="programlisting"><span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">bool</span> <span class="identifier">C</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="special">...</span> <span class="identifier">E</span><span class="special">&gt;</span> <span class="keyword">using</span> <span class="identifier">mp_if_c</span> <span class="special">=</span> <span class="comment">/*...*/</span><span class="special">;</span>
</pre>
<p>
<code class="computeroutput"><span class="identifier">mp_if_c</span><span class="special">&lt;</span><span class="identifier">B</span><span class="special">,</span> <span class="identifier">T</span><span class="special">,</span> <span class="identifier">E</span><span class="special">&gt;</span></code>
is an alias for <code class="computeroutput"><span class="identifier">T</span></code> when
<code class="computeroutput"><span class="identifier">B</span></code> is <code class="computeroutput"><span class="keyword">true</span></code>,
for <code class="computeroutput"><span class="identifier">E</span></code> otherwise.
<code class="computeroutput"><span class="identifier">mp_if_c</span><span class="special">&lt;</span><span class="keyword">true</span><span class="special">,</span> <span class="identifier">T</span><span class="special">,</span> <span class="identifier">E</span><span class="special">...&gt;</span></code>
is an alias for <code class="computeroutput"><span class="identifier">T</span></code>. <code class="computeroutput"><span class="identifier">mp_if_c</span><span class="special">&lt;</span><span class="keyword">false</span><span class="special">,</span> <span class="identifier">T</span><span class="special">,</span> <span class="identifier">E</span><span class="special">&gt;</span></code> is an alias for <code class="computeroutput"><span class="identifier">E</span></code>.
Otherwise, the result is a substitution failure.
</p>
<pre class="programlisting"><span class="keyword">using</span> <span class="identifier">R1</span> <span class="special">=</span> <span class="identifier">mp_if_c</span><span class="special">&lt;</span><span class="keyword">true</span><span class="special">,</span> <span class="keyword">int</span><span class="special">,</span> <span class="keyword">void</span><span class="special">&gt;;</span> <span class="comment">// int</span>
<span class="keyword">using</span> <span class="identifier">R2</span> <span class="special">=</span> <span class="identifier">mp_if_c</span><span class="special">&lt;</span><span class="identifier">flase</span><span class="special">,</span> <span class="keyword">int</span><span class="special">,</span> <span class="keyword">void</span><span class="special">&gt;;</span> <span class="comment">// void</span>
<span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">class</span> <span class="identifier">I</span><span class="special">&gt;</span> <span class="keyword">using</span> <span class="identifier">void_if_5</span> <span class="special">=</span> <span class="identifier">mp_if_c</span><span class="special">&lt;</span><span class="identifier">I</span><span class="special">::</span><span class="identifier">value</span> <span class="special">==</span> <span class="number">5</span><span class="special">,</span> <span class="keyword">void</span><span class="special">&gt;;</span> <span class="comment">// `void` when `I::value` is 5, substitution failure otherwise</span>
</pre>
</div>
<div class="section">
<div class="titlepage"><div><div><h4 class="title">
<a name="mp11.reference.utility.mp_if_c_t_e"></a><a class="link" href="mp11.html#mp11.reference.utility.mp_if_c_t_e" title="mp_if&lt;C, T, E...&gt;"><code class="computeroutput"><span class="identifier">mp_if</span><span class="special">&lt;</span><span class="identifier">C</span><span class="special">,</span>
<span class="identifier">T</span><span class="special">,</span> <span class="identifier">E</span><span class="special">...&gt;</span></code></a>
</h4></div></div></div>
<pre class="programlisting"><span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">class</span> <span class="identifier">C</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">E</span><span class="special">...&gt;</span> <span class="keyword">using</span> <span class="identifier">mp_if</span> <span class="special">=</span> <span class="identifier">mp_if_c</span><span class="special">&lt;</span><span class="keyword">static_cast</span><span class="special">&lt;</span><span class="keyword">bool</span><span class="special">&gt;(</span><span class="identifier">C</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="identifier">E</span><span class="special">...&gt;;</span>
</pre>
<p>
Like <code class="computeroutput"><span class="identifier">mp_if_c</span></code>, but the first
argument is a type.
</p>
</div>
<div class="section">
<div class="titlepage"><div><div><h4 class="title">
<a name="mp11.reference.utility.mp_if_c_t_e"></a><a class="link" href="mp11.html#mp11.reference.utility.mp_if_c_t_e" title="mp_if&lt;C, T, E&gt;"><code class="computeroutput"><span class="identifier">mp_if</span><span class="special">&lt;</span><span class="identifier">C</span><span class="special">,</span>
<span class="identifier">T</span><span class="special">,</span> <span class="identifier">E</span><span class="special">&gt;</span></code></a>
</h4></div></div></div>
<pre class="programlisting"><span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">class</span> <span class="identifier">C</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">E</span><span class="special">&gt;</span> <span class="keyword">using</span> <span class="identifier">mp_if</span> <span class="special">=</span> <span class="identifier">mp_if_c</span><span class="special">&lt;</span><span class="keyword">static_cast</span><span class="special">&lt;</span><span class="keyword">bool</span><span class="special">&gt;(</span><span class="identifier">C</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="identifier">E</span><span class="special">&gt;;</span>
</pre>
<p>
<code class="computeroutput"><span class="identifier">mp_if</span><span class="special">&lt;</span><span class="identifier">C</span><span class="special">,</span> <span class="identifier">T</span><span class="special">,</span> <span class="identifier">E</span><span class="special">&gt;</span></code>
is an alias for <code class="computeroutput"><span class="identifier">T</span></code> when
<code class="computeroutput"><span class="identifier">C</span><span class="special">::</span><span class="identifier">value</span></code> is <code class="computeroutput"><span class="keyword">true</span></code>,
for <code class="computeroutput"><span class="identifier">E</span></code> otherwise.
</p>
</div>
<div class="section">
<div class="titlepage"><div><div><h4 class="title">
<a name="mp11.reference.utility.mp_eval_if_c_b_t_f_u"></a><a class="link" href="mp11.html#mp11.reference.utility.mp_eval_if_c_b_t_f_u" title="mp_eval_if_c&lt;B, T, F, U...&gt;"><code class="computeroutput"><span class="identifier">mp_eval_if_c</span><span class="special">&lt;</span><span class="identifier">B</span><span class="special">,</span> <span class="identifier">T</span><span class="special">,</span> <span class="identifier">F</span><span class="special">,</span>
<a name="mp11.reference.utility.mp_eval_if_c_c_t_f_u"></a><a class="link" href="mp11.html#mp11.reference.utility.mp_eval_if_c_c_t_f_u" title="mp_eval_if_c&lt;C, T, F, U...&gt;"><code class="computeroutput"><span class="identifier">mp_eval_if_c</span><span class="special">&lt;</span><span class="identifier">C</span><span class="special">,</span> <span class="identifier">T</span><span class="special">,</span> <span class="identifier">F</span><span class="special">,</span>
<span class="identifier">U</span><span class="special">...&gt;</span></code></a>
</h4></div></div></div>
<pre class="programlisting"><span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">bool</span> <span class="identifier">C</span><span class="special">,</span> <span class="keyword">class</span> <span class="identifier">T</span><span class="special">,</span> <span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">class</span><span class="special">...&gt;</span> <span class="keyword">class</span> <span class="identifier">F</span><span class="special">,</span> <span class="keyword">class</span><span class="special">...</span> <span class="identifier">U</span><span class="special">&gt;</span> <span class="keyword">using</span> <span class="identifier">mp_eval_if_c</span> <span class="special">=</span> <span class="comment">/*...*/</span><span class="special">;</span>
</pre>
<p>
<code class="computeroutput"><span class="identifier">mp_eval_if_c</span><span class="special">&lt;</span><span class="identifier">B</span><span class="special">,</span> <span class="identifier">T</span><span class="special">,</span> <span class="identifier">F</span><span class="special">,</span>
<code class="computeroutput"><span class="identifier">mp_eval_if_c</span><span class="special">&lt;</span><span class="identifier">C</span><span class="special">,</span> <span class="identifier">T</span><span class="special">,</span> <span class="identifier">F</span><span class="special">,</span>
<span class="identifier">U</span><span class="special">...&gt;</span></code>
is an alias for <code class="computeroutput"><span class="identifier">T</span></code> when
<code class="computeroutput"><span class="identifier">B</span></code> is <code class="computeroutput"><span class="keyword">true</span></code>,
<code class="computeroutput"><span class="identifier">C</span></code> is <code class="computeroutput"><span class="keyword">true</span></code>,
for <code class="computeroutput"><span class="identifier">F</span><span class="special">&lt;</span><span class="identifier">U</span><span class="special">...&gt;</span></code>
otherwise. Its purpose is to avoid evaluating <code class="computeroutput"><span class="identifier">F</span><span class="special">&lt;</span><span class="identifier">U</span><span class="special">...&gt;</span></code> when the condition is <code class="computeroutput"><span class="keyword">true</span></code> as it may not be valid in this case.
</p>
@@ -1264,6 +1367,18 @@
</div>
<div class="section">
<div class="titlepage"><div><div><h4 class="title">
<a name="mp11.reference.utility.mp_eval_if_q_c_t_q_u"></a><a class="link" href="mp11.html#mp11.reference.utility.mp_eval_if_q_c_t_q_u" title="mp_eval_if_q&lt;C, T, Q, U...&gt;"><code class="computeroutput"><span class="identifier">mp_eval_if_q</span><span class="special">&lt;</span><span class="identifier">C</span><span class="special">,</span> <span class="identifier">T</span><span class="special">,</span> <span class="identifier">Q</span><span class="special">,</span>
<span class="identifier">U</span><span class="special">...&gt;</span></code></a>
</h4></div></div></div>
<pre class="programlisting"><span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">class</span> <span class="identifier">C</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">Q</span><span class="special">,</span> <span class="keyword">class</span><span class="special">...</span> <span class="identifier">U</span><span class="special">&gt;</span> <span class="keyword">using</span> <span class="identifier">mp_eval_if_q</span> <span class="special">=</span> <span class="identifier">mp_eval_if</span><span class="special">&lt;</span><span class="identifier">C</span><span class="special">,</span> <span class="identifier">T</span><span class="special">,</span> <span class="identifier">Q</span><span class="special">::</span><span class="keyword">template</span> <span class="identifier">fn</span><span class="special">,</span> <span class="identifier">U</span><span class="special">...&gt;;</span>
</pre>
<p>
Like <code class="computeroutput"><span class="identifier">mp_eval_if</span></code>, but takes
a quoted metafunction.
</p>
</div>
<div class="section">
<div class="titlepage"><div><div><h4 class="title">
<a name="mp11.reference.utility.mp_valid_f_t"></a><a class="link" href="mp11.html#mp11.reference.utility.mp_valid_f_t" title="mp_valid&lt;F, T...&gt;"><code class="computeroutput"><span class="identifier">mp_valid</span><span class="special">&lt;</span><span class="identifier">F</span><span class="special">,</span> <span class="identifier">T</span><span class="special">...&gt;</span></code></a>
</h4></div></div></div>
<pre class="programlisting"><span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">class</span><span class="special">...&gt;</span> <span class="keyword">class</span> <span class="identifier">F</span><span class="special">,</span> <span class="keyword">class</span><span class="special">...</span> <span class="identifier">T</span><span class="special">&gt;</span> <span class="keyword">using</span> <span class="identifier">mp_valid</span> <span class="special">=</span> <span class="comment">/*...*/</span><span class="special">;</span>
@@ -2087,6 +2202,21 @@
but does not perform short-circuit evaluation.
</p>
</div>
<div class="section">
<div class="titlepage"><div><div><h4 class="title">
<a name="mp11.reference.function.mp_same_t"></a><a class="link" href="mp11.html#mp11.reference.function.mp_same_t" title="mp_same&lt;T...&gt;"><code class="computeroutput"><span class="identifier">mp_same</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">...&gt;</span></code></a>
</h4></div></div></div>
<pre class="programlisting"><span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">class</span><span class="special">...</span> <span class="identifier">T</span><span class="special">&gt;</span> <span class="keyword">using</span> <span class="identifier">mp_same</span> <span class="special">=</span> <span class="comment">/*...*/</span><span class="special">;</span>
</pre>
<p>
<code class="computeroutput"><span class="identifier">mp_same</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">...&gt;</span></code>
is <code class="computeroutput"><span class="identifier">mp_true</span></code> if all the types
in <code class="computeroutput"><span class="identifier">T</span><span class="special">...</span></code>
are the same type, <code class="computeroutput"><span class="identifier">mp_false</span></code>
otherwise. <code class="computeroutput"><span class="identifier">mp_same</span><span class="special">&lt;&gt;</span></code>
is <code class="computeroutput"><span class="identifier">mp_true</span></code>.
</p>
</div>
</div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
@@ -2299,7 +2429,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 17, 2017 at 17:44:23 GMT</small></p></td>
<td align="left"><p><small>Last revised: May 18, 2017 at 23:57:52 GMT</small></p></td>
<td align="right"><div class="copyright-footer"></div></td>
</tr></table>
<hr>

View File

@@ -87,6 +87,62 @@ tuple element; we use a (C++14) lambda that calls `test_result`. (In pure C++11,
function object with a templated `operator()` and pass that to `tuple_for_each` directly.)
[endsect]
[section Writing `common_type` specializations]
The standard trait `std::common_type`, used to obtain a type to which all of its arguments can convert without
unnecessary loss of precision, can be user-specialized when its default implementation (based on the ternary `?:`
operator) is unsuitable.
Let's write a `common_type` specialization for two `std::tuple` arguments. For that, we need a metafunction that
applies `std::common_type` to each pair of elements and gathers the results into a tuple:
template<class Tp1, class Tp2> using common_tuple = mp_transform<std::common_type_t, Tp1, Tp2>;
then specialize `common_type` to use it:
namespace std
{
template<class... T1, class... T2> struct common_type<std::tuple<T1...>, std::tuple<T2...>>: mp_defer<common_tuple, std::tuple<T1...>, std::tuple<T2...>>
{
};
} // std
(There is no need to specialize `std::common_type` for more than two arguments - it takes care of synthesizing the appropriate semantics from
the binary case.)
The subtlety here is the use of `mp_defer`. We could have defined a nested `type` to `common_tuple<std::tuple<T1...>, std::tuple<T2...>>`,
and it would still have worked in all valid cases. By letting `mp_defer` define `type`, though, we make our specialization /SFINAE-friendly/.
That is, when our `common_tuple` causes a substitution failure instead of a hard error, `mp_defer` will not define a nested `type`,
and `common_type_t`, which is defined as `typename common_type<...>::type`, will also cause a substitution failure.
As another example, consider the hypothetical type `expected<T, E...>` that represents either a successful return with a value of `T`,
or an unsucessful return with an error code of some type in the list `E...`. The common type of `expected<T1, E1, E2, E3>` and
`expected<T2, E1, E4, E5>` is `expected<std::common_type_t<T1, T2>, E1, E2, E3, E4, E5>`. That is, the possible return values are
combined into their common type, and we take the union of the set of error types.
Therefore,
template<class T1, class E1, class T2, class E2> using common_expected = mp_rename<mp_push_front<mp_unique<mp_append<E1, E2>>, std::common_type_t<T1, T2>>, expected>;
namespace std
{
template<class T1, class... E1, class T2, class... E2> struct common_type<expected<T1, E1...>, expected<T2, E2...>>: mp_defer<common_expected, T1, mp_list<E1...>, T2, mp_list<E2...>>
{
};
} // std
Here we've taken a different tack; instead of passing the `expected` types to `common_expected`, we're passing the `T` types and lists of
the `E` types. This makes our job easier. `mp_unique<mp_append<E1, E2>>` gives us the concatenation of `E1` and `E2` with the duplicates
removed; we then add `std::common_type_t<T1, T2>` to the front via `mp_push_front`; and finally, we `mp_rename` the resultant `mp_list`
to `expected`.
[endsect]
[section Fixing `tuple_cat`]
The article [@http://pdimov.com/cpp2/simple_cxx11_metaprogramming.html Simple C++11 metaprogramming] builds an
@@ -148,7 +204,7 @@ that support `tuple_size`, `tuple_element`, and `get`), while our implementation
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 ) );
auto result = ::tuple_cat( t1, 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>&&>`,
@@ -193,10 +249,10 @@ 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:
What we need is, given a tuple-like type `Tp`, to obtain `mp_list<std::tuple_element<0, Tp>::type, std::tuple_element<1, Tp>::type,
..., std::tuple_element<N-1, Tp>::type>`, 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, class I> using tuple_element = typename std::tuple_element<I::value, T>::type;
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>`.)
@@ -224,7 +280,7 @@ With all these fixes applied, our fully operational `tuple_cat` now looks like t
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, class I> using tuple_element = typename std::tuple_element<I::value, T>::type;
template<class T> using from_tuple_like = mp_product<tuple_element, mp_list<T>, mp_iota<std::tuple_size<T>>>;
template<class... Tp,

View File

@@ -37,4 +37,10 @@ If no such type exists, the last one is returned. `mp_or<>` is `mp_false`. Simil
`mp_or`, but does not perform short-circuit evaluation.
[endsect]
[section `mp_same<T...>`]
template<class... T> using mp_same = /*...*/;
`mp_same<T...>` is `mp_true` if all the types in `T...` are the same type, `mp_false` otherwise. `mp_same<>` is `mp_true`.
[endsect]
[endsect:function]

View File

@@ -23,22 +23,27 @@
template<class... T> struct mp_inherit: T... {};
[endsect]
[section `mp_if_c<B, T, E>`]
template<bool C, class T, class E> using mp_if_c = /*...*/;
[section `mp_if_c<C, T, E...>`]
template<bool C, class T, class... E> using mp_if_c = /*...*/;
`mp_if_c<B, T, E>` is an alias for `T` when `B` is `true`, for `E` otherwise.
`mp_if_c<true, T, E...>` is an alias for `T`. `mp_if_c<false, T, E>` is an alias for `E`. Otherwise, the result is a substitution failure.
using R1 = mp_if_c<true, int, void>; // int
using R2 = mp_if_c<flase, int, void>; // void
template<class I> using void_if_5 = mp_if_c<I::value == 5, void>; // `void` when `I::value` is 5, substitution failure otherwise
[endsect]
[section `mp_if<C, T, E>`]
template<class C, class T, class E> using mp_if = mp_if_c<static_cast<bool>(C::value), T, E>;
[section `mp_if<C, T, E...>`]
template<class C, class T, class E...> using mp_if = mp_if_c<static_cast<bool>(C::value), T, E...>;
`mp_if<C, T, E>` is an alias for `T` when `C::value` is `true`, for `E` otherwise.
Like `mp_if_c`, but the first argument is a type.
[endsect]
[section `mp_eval_if_c<B, T, F, U...>`]
[section `mp_eval_if_c<C, T, F, U...>`]
template<bool C, class T, template<class...> class F, class... U> using mp_eval_if_c = /*...*/;
`mp_eval_if_c<B, T, F, U...>` is an alias for `T` when `B` is `true`, for `F<U...>` otherwise. Its purpose
`mp_eval_if_c<C, T, F, U...>` is an alias for `T` when `C` is `true`, for `F<U...>` otherwise. Its purpose
is to avoid evaluating `F<U...>` when the condition is `true` as it may not be valid in this case.
[endsect]
@@ -48,6 +53,12 @@ is to avoid evaluating `F<U...>` when the condition is `true` as it may not be v
Like `mp_eval_if_c`, but the first argument is a type.
[endsect]
[section `mp_eval_if_q<C, T, Q, U...>`]
template<class C, class T, class Q, class... U> using mp_eval_if_q = mp_eval_if<C, T, Q::template fn, U...>;
Like `mp_eval_if`, but takes a quoted metafunction.
[endsect]
[section `mp_valid<F, T...>`]
template<template<class...> class F, class... T> using mp_valid = /*...*/;

View File

@@ -12,6 +12,7 @@
#include <boost/mp11/set.hpp>
#include <boost/mp11/integral.hpp>
#include <boost/mp11/utility.hpp>
#include <boost/mp11/function.hpp>
#include <boost/mp11/detail/mp_count.hpp>
#include <boost/mp11/detail/mp_plus.hpp>
#include <boost/mp11/detail/mp_map_find.hpp>
@@ -59,7 +60,9 @@ template<class L, class V, template<class...> class F> using mp_fold = typename
namespace detail
{
template<template<class...> class F, class... L> struct mp_transform_impl;
template<template<class...> class F, class... L> struct mp_transform_impl
{
};
template<template<class...> class F, template<class...> class L, class... T> struct mp_transform_impl<F, L<T...>>
{
@@ -68,19 +71,33 @@ template<template<class...> class F, template<class...> class L, class... T> str
template<template<class...> class F, template<class...> class L1, class... T1, template<class...> class L2, class... T2> struct mp_transform_impl<F, L1<T1...>, L2<T2...>>
{
static_assert( sizeof...(T1) == sizeof...(T2), "The arguments of mp_transform should be of the same size" );
using type = L1<F<T1,T2>...>;
};
template<template<class...> class F, template<class...> class L1, class... T1, template<class...> class L2, class... T2, template<class...> class L3, class... T3> struct mp_transform_impl<F, L1<T1...>, L2<T2...>, L3<T3...>>
{
static_assert( sizeof...(T1) == sizeof...(T2) && sizeof...(T1) == sizeof...(T3), "The arguments of mp_transform should be of the same size" );
using type = L1<F<T1,T2,T3>...>;
};
#if BOOST_WORKAROUND( BOOST_MSVC, == 1900 ) || BOOST_WORKAROUND( BOOST_GCC, < 40800 )
template<class... L> using mp_same_size_1 = mp_same<mp_size<L>...>;
template<class... L> struct mp_same_size_2: mp_defer<mp_same_size_1, L...> {};
#endif
} // namespace detail
template<template<class...> class F, class... L> using mp_transform = typename detail::mp_transform_impl<F, L...>::type;
#if BOOST_WORKAROUND( BOOST_MSVC, == 1900 ) || BOOST_WORKAROUND( BOOST_GCC, < 40800 )
template<template<class...> class F, class... L> using mp_transform = typename mp_if<typename detail::mp_same_size_2<L...>::type, detail::mp_transform_impl<F, L...>>::type;
#else
template<template<class...> class F, class... L> using mp_transform = typename mp_if<mp_same<mp_size<L>...>, detail::mp_transform_impl<F, L...>>::type;
#endif
template<class Q, class... L> using mp_transform_q = mp_transform<Q::template fn, L...>;
namespace detail
@@ -88,8 +105,6 @@ namespace detail
template<template<class...> class F, template<class...> class L1, class... T1, template<class...> class L2, class... T2, template<class...> class L3, class... T3, template<class...> class L4, class... T4, class... L> struct mp_transform_impl<F, L1<T1...>, L2<T2...>, L3<T3...>, L4<T4...>, L...>
{
static_assert( sizeof...(T1) == sizeof...(T2) && sizeof...(T1) == sizeof...(T3) && sizeof...(T1) == sizeof...(T4), "The arguments of mp_transform should be of the same size" );
using A1 = L1<mp_list<T1, T2, T3, T4>...>;
template<class V, class T> using _f = mp_transform<mp_push_back, V, T>;

View File

@@ -33,9 +33,11 @@ template<class... T> struct mp_inherit: T... {};
namespace detail
{
template<bool C, class T, class E> struct mp_if_c_impl;
template<bool C, class T, class... E> struct mp_if_c_impl
{
};
template<class T, class E> struct mp_if_c_impl<true, T, E>
template<class T, class... E> struct mp_if_c_impl<true, T, E...>
{
using type = T;
};
@@ -47,29 +49,8 @@ template<class T, class E> struct mp_if_c_impl<false, T, E>
} // namespace detail
template<bool C, class T, class E> using mp_if_c = typename detail::mp_if_c_impl<C, T, E>::type;
template<class C, class T, class E> using mp_if = typename detail::mp_if_c_impl<static_cast<bool>(C::value), T, E>::type;
// mp_eval_if, mp_eval_if_c
namespace detail
{
template<bool C, class T, template<class...> class F, class... U> struct mp_eval_if_c_impl;
template<class T, template<class...> class F, class... U> struct mp_eval_if_c_impl<true, T, F, U...>
{
using type = T;
};
template<class T, template<class...> class F, class... U> struct mp_eval_if_c_impl<false, T, F, U...>
{
using type = F<U...>;
};
} // namespace detail
template<bool C, class T, template<class...> class F, class... U> using mp_eval_if_c = typename detail::mp_eval_if_c_impl<C, T, F, U...>::type;
template<class C, class T, template<class...> class F, class... U> using mp_eval_if = typename detail::mp_eval_if_c_impl<static_cast<bool>(C::value), T, F, U...>::type;
template<bool C, class T, class... E> using mp_if_c = typename detail::mp_if_c_impl<C, T, E...>::type;
template<class C, class T, class... E> using mp_if = typename detail::mp_if_c_impl<static_cast<bool>(C::value), T, E...>::type;
// mp_valid
// implementation by Bruno Dutra (by the name is_evaluable)
@@ -105,37 +86,58 @@ struct mp_no_type
template<template<class...> class F, class... T> using mp_defer = mp_if<mp_valid<F, T...>, detail::mp_defer_impl<F, T...>, detail::mp_no_type>;
// mp_quote
template<template<class...> class F> struct mp_quote
{
#if defined( BOOST_MSVC ) && BOOST_WORKAROUND( BOOST_MSVC, <= 1910 && BOOST_MSVC >= 1900 )
#else
private:
#endif
template<class... T> struct _fn { using type = F<T...>; };
public:
// the indirection through _fn works around the language inability
// to expand T... into a fixed parameter list of an alias template
template<class... T> using fn = typename _fn<T...>::type;
};
// mp_unquote
// mp_eval_if, mp_eval_if_c
namespace detail
{
template<class Q, class... T> struct mp_invoke_impl
template<bool C, class T, template<class...> class F, class... U> struct mp_eval_if_c_impl;
template<class T, template<class...> class F, class... U> struct mp_eval_if_c_impl<true, T, F, U...>
{
using type = typename Q::template fn<T...>;
using type = T;
};
template<class T, template<class...> class F, class... U> struct mp_eval_if_c_impl<false, T, F, U...>: mp_defer<F, U...>
{
};
} // namespace detail
template<bool C, class T, template<class...> class F, class... U> using mp_eval_if_c = typename detail::mp_eval_if_c_impl<C, T, F, U...>::type;
template<class C, class T, template<class...> class F, class... U> using mp_eval_if = typename detail::mp_eval_if_c_impl<static_cast<bool>(C::value), T, F, U...>::type;
template<class C, class T, class Q, class... U> using mp_eval_if_q = typename detail::mp_eval_if_c_impl<static_cast<bool>(C::value), T, Q::template fn, U...>::type;
// mp_quote
template<template<class...> class F> struct mp_quote
{
// the indirection through mp_defer works around the language inability
// to expand T... into a fixed parameter list of an alias template
template<class... T> using fn = typename mp_defer<F, T...>::type;
};
// mp_invoke
#if BOOST_WORKAROUND( BOOST_MSVC, < 1900 )
namespace detail
{
template<class Q, class... T> struct mp_invoke_impl: mp_defer<Q::template fn, T...> {};
} // namespace detail
template<class Q, class... T> using mp_invoke = typename detail::mp_invoke_impl<Q, T...>::type;
#elif BOOST_WORKAROUND( BOOST_GCC, < 50000 )
template<class Q, class... T> using mp_invoke = typename mp_defer<Q::template fn, T...>::type;
#else
template<class Q, class... T> using mp_invoke = typename Q::template fn<T...>;
#endif
} // namespace mp11
} // namespace boost

View File

@@ -35,6 +35,7 @@ run mp_apply_q.cpp : : : $(REQ) ;
run mp_assign.cpp : : : $(REQ) ;
run mp_clear.cpp : : : $(REQ) ;
run mp_transform.cpp : : : $(REQ) ;
run mp_transform_sf.cpp : : : $(REQ) ;
run mp_transform_if.cpp : : : $(REQ) ;
run mp_fill.cpp : : : $(REQ) ;
run mp_count.cpp : : : $(REQ) ;
@@ -75,11 +76,14 @@ run integral.cpp : : : $(REQ) ;
run mp_identity.cpp : : : $(REQ) ;
run mp_inherit.cpp : : : $(REQ) ;
run mp_if.cpp : : : $(REQ) ;
run mp_if_sf.cpp : : : $(REQ) ;
run mp_eval_if.cpp : : : $(REQ) ;
run mp_eval_if_sf.cpp : : : $(REQ) ;
run mp_valid.cpp : : : $(REQ) ;
run mp_defer.cpp : : : $(REQ) ;
run mp_quote.cpp : : : $(REQ) ;
run mp_invoke.cpp : : : $(REQ) ;
run mp_invoke_sf.cpp : : : $(REQ) ;
# integer_sequence
run integer_sequence.cpp : : : $(REQ) ;

View File

@@ -1,5 +1,5 @@
// Copyright 2015 Peter Dimov.
// Copyright 2015, 2017 Peter Dimov.
//
// Distributed under the Boost Software License, Version 1.0.
//
@@ -21,19 +21,32 @@ int main()
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_eval_if_c<false, char[], mp_identity, void()>, mp_identity<void()>>));
using boost::mp11::mp_eval_if;
using boost::mp11::mp_eval_if_q;
using boost::mp11::mp_quote;
using qt_identity = mp_quote<mp_identity>;
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_eval_if<std::true_type, char[], mp_identity, void, void, void>, char[]>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_eval_if<std::false_type, char[], mp_identity, void()>, mp_identity<void()>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_eval_if_q<std::true_type, char[], qt_identity, void, void, void>, char[]>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_eval_if_q<std::false_type, char[], qt_identity, void()>, mp_identity<void()>>));
using boost::mp11::mp_int;
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_eval_if<mp_int<-7>, char[], mp_identity, void, void, void>, char[]>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_eval_if<mp_int<0>, char[], mp_identity, void()>, mp_identity<void()>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_eval_if_q<mp_int<-7>, char[], qt_identity, void, void, void>, char[]>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_eval_if_q<mp_int<0>, char[], qt_identity, void()>, mp_identity<void()>>));
using boost::mp11::mp_size_t;
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_eval_if<mp_size_t<14>, char[], mp_identity, void, void, void>, char[]>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_eval_if<mp_size_t<0>, char[], mp_identity, void()>, mp_identity<void()>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_eval_if_q<mp_size_t<14>, char[], qt_identity, void, void, void>, char[]>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_eval_if_q<mp_size_t<0>, char[], qt_identity, void()>, mp_identity<void()>>));
return boost::report_errors();
}

47
test/mp_eval_if_sf.cpp Normal file
View File

@@ -0,0 +1,47 @@
// Copyright 2017 Peter Dimov.
//
// Distributed under the Boost Software License, Version 1.0.
//
// See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt
#include <boost/mp11/utility.hpp>
#include <boost/core/lightweight_test_trait.hpp>
#include <type_traits>
using boost::mp11::mp_eval_if;
using boost::mp11::mp_eval_if_q;
using boost::mp11::mp_identity_t;
using boost::mp11::mp_valid;
using boost::mp11::mp_quote;
template<class C, class... A> using eval_if = mp_eval_if<C, void, mp_identity_t, A...>;
int main()
{
BOOST_TEST_TRAIT_TRUE((mp_valid<eval_if, std::true_type>));
BOOST_TEST_TRAIT_TRUE((mp_valid<eval_if, std::true_type, void>));
BOOST_TEST_TRAIT_TRUE((mp_valid<eval_if, std::true_type, void, void>));
BOOST_TEST_TRAIT_TRUE((mp_valid<eval_if, std::true_type, void, void, void>));
BOOST_TEST_TRAIT_FALSE((mp_valid<eval_if, std::false_type>));
BOOST_TEST_TRAIT_TRUE((mp_valid<eval_if, std::false_type, void>));
BOOST_TEST_TRAIT_FALSE((mp_valid<eval_if, std::false_type, void, void>));
BOOST_TEST_TRAIT_FALSE((mp_valid<eval_if, std::false_type, void, void, void>));
using Qi = mp_quote<mp_identity_t>;
BOOST_TEST_TRAIT_TRUE((mp_valid<mp_eval_if_q, std::true_type, void, Qi>));
BOOST_TEST_TRAIT_TRUE((mp_valid<mp_eval_if_q, std::true_type, void, Qi, void>));
BOOST_TEST_TRAIT_TRUE((mp_valid<mp_eval_if_q, std::true_type, void, Qi, void, void>));
BOOST_TEST_TRAIT_TRUE((mp_valid<mp_eval_if_q, std::true_type, void, Qi, void, void, void>));
BOOST_TEST_TRAIT_FALSE((mp_valid<mp_eval_if_q, std::false_type, void, Qi>));
BOOST_TEST_TRAIT_TRUE((mp_valid<mp_eval_if_q, std::false_type, void, Qi, void>));
BOOST_TEST_TRAIT_FALSE((mp_valid<mp_eval_if_q, std::false_type, void, Qi, void, void>));
BOOST_TEST_TRAIT_FALSE((mp_valid<mp_eval_if_q, std::false_type, void, Qi, void, void, void>));
return boost::report_errors();
}

24
test/mp_if_sf.cpp Normal file
View File

@@ -0,0 +1,24 @@
// Copyright 2017 Peter Dimov.
//
// Distributed under the Boost Software License, Version 1.0.
//
// See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt
#include <boost/mp11/utility.hpp>
#include <boost/core/lightweight_test_trait.hpp>
#include <type_traits>
int main()
{
using boost::mp11::mp_if;
using boost::mp11::mp_valid;
BOOST_TEST_TRAIT_FALSE((mp_valid<mp_if, std::false_type, void>));
BOOST_TEST_TRAIT_TRUE((mp_valid<mp_if, std::false_type, void, void>));
BOOST_TEST_TRAIT_FALSE((mp_valid<mp_if, std::false_type, void, void, void>));
return boost::report_errors();
}

33
test/mp_invoke_sf.cpp Normal file
View File

@@ -0,0 +1,33 @@
// Copyright 2015, 2017 Peter Dimov.
//
// Distributed under the Boost Software License, Version 1.0.
//
// See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt
#include <boost/mp11/utility.hpp>
#include <boost/core/lightweight_test_trait.hpp>
#include <type_traits>
using boost::mp11::mp_invoke;
using boost::mp11::mp_quote;
using boost::mp11::mp_valid;
using boost::mp11::mp_identity_t;
int main()
{
BOOST_TEST_TRAIT_FALSE((mp_valid<mp_invoke>));
BOOST_TEST_TRAIT_FALSE((mp_valid<mp_invoke, void>));
BOOST_TEST_TRAIT_FALSE((mp_valid<mp_invoke, void, void>));
BOOST_TEST_TRAIT_FALSE((mp_valid<mp_invoke, void, void, void>));
using Qi = mp_quote<mp_identity_t>;
BOOST_TEST_TRAIT_FALSE((mp_valid<mp_invoke, Qi>));
BOOST_TEST_TRAIT_TRUE((mp_valid<mp_invoke, Qi, void>));
BOOST_TEST_TRAIT_FALSE((mp_valid<mp_invoke, Qi, void, void>));
return boost::report_errors();
}

42
test/mp_transform_sf.cpp Normal file
View File

@@ -0,0 +1,42 @@
// Copyright 2017 Peter Dimov.
//
// Distributed under the Boost Software License, Version 1.0.
//
// See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt
#include <boost/mp11/algorithm.hpp>
#include <boost/mp11/utility.hpp>
#include <boost/mp11/list.hpp>
#include <boost/core/lightweight_test_trait.hpp>
using boost::mp11::mp_transform;
using boost::mp11::mp_list;
using boost::mp11::mp_valid;
template<class...> using F = void;
template<class... L> using transform = mp_transform<F, L...>;
int main()
{
BOOST_TEST_TRAIT_FALSE((mp_valid<transform>));
BOOST_TEST_TRAIT_FALSE((mp_valid<transform, void>));
BOOST_TEST_TRAIT_FALSE((mp_valid<transform, void, void>));
BOOST_TEST_TRAIT_FALSE((mp_valid<transform, void, void, void>));
BOOST_TEST_TRAIT_FALSE((mp_valid<transform, void, void, void, void>));
BOOST_TEST_TRAIT_FALSE((mp_valid<transform, void, void, void, void, void>));
#if !BOOST_WORKAROUND( BOOST_MSVC, <= 1800 )
BOOST_TEST_TRAIT_TRUE((mp_valid<transform, mp_list<>>));
#endif
BOOST_TEST_TRAIT_FALSE((mp_valid<transform, mp_list<>, mp_list<void>>));
BOOST_TEST_TRAIT_FALSE((mp_valid<transform, mp_list<>, mp_list<>, mp_list<void>>));
BOOST_TEST_TRAIT_FALSE((mp_valid<transform, mp_list<>, mp_list<>, mp_list<>, mp_list<void>>));
BOOST_TEST_TRAIT_FALSE((mp_valid<transform, mp_list<>, mp_list<>, mp_list<>, mp_list<>, mp_list<void>>));
return boost::report_errors();
}