<html>
<head><title>N4144, Searching and Manipulation of Parameter Packs</title></head>
<body>
<table border=0>
<tr><td><b>Doc No:</b></td><td>N4144</td></tr>
<tr><td><b>Date:</b></td><td>2014-09-11</td></tr>
<tr><td><b>Reply to:</b></td><td><tt>stdbill.h@pobox.com</tt></td></tr>
</table>
<center>
<h2>Searching and Manipulation of Parameter Packs</h2>
<h3>Bill Seymour<br>Stephan T. Lavavej<br>2014-09-11</h3>
</center>
<hr size=5>
<h3>Abstract:</h3>

This paper proposes that mechanisms for finding types in parameter packs,
and for adding and removing types to/from parameter packs,
be added to the standard library.

<p><hr size=5>
<h3>Revision history:</h3>
This paper is a revision of
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4115.html">N4115</a>
which proposed only the <tt>packer</tt>, <tt>is_contained_in</tt> and
<tt>contains_types</tt> class templates along with the <tt>is_contained_in_v</tt>
and <tt>contains_types_v</tt> value templates.

<p><hr size=5>
<h3>The basic idea:</h3>
This paper proposes seven new class templates, two new
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3854.htm">value
templates</a>, and four new
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3655.pdf">template
aliases</a> for <tt>&lt;type_traits&gt;</tt>.
<ul>
<li><tt>packer</tt> is a variadic class template the only purpose of which
    is to hold a parameter pack.
<p><li><tt>is_contained_in</tt> and <tt>contains_types</tt> compile to
    either <tt>true_type</tt> or <tt>false_type</tt> to report
    whether a parameter pack contains one or more types.
<p><li><tt>add_to</tt> and <tt>unique_add_to</tt> add zero or more types
    to a parameter pack.
<p><li><tt>remove_from</tt> removes zero or more types from a parameter pack.
<p><li><tt>uniqueify</tt> removes duplicate types from a parameter pack.
</ul>

<p><a href="#notdoneant">Some of the proposed standardese remains to be written.</a>

<p>As proof of concept, possible implementations (not necessarily the best)
of the various class templates are shown; and <a href="#appa">Appendix A</a>
contains a listing for a crude test program that displays the results
of instantiation on the standard output.

<p><a name="packer"><hr></a>
<h4>A class template that just holds a parameter pack:</h4>
<pre>
    template &lt;class... Args&gt; struct packer { };
</pre>
This is inspired by <tt>std::tuple</tt>, but it has no members,
so it could serve as an empty base class,
and an object of the ultimate type could always be instantiated
(even if the parameter pack contains <tt>void</tt>
or some type that lacks a default constructor).
<!--
<p>The member type, <tt>type</tt>, is a helper for the <tt>add_to_t</tt> and <tt>unique_add_to_t</tt>
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3655.pdf">template
aliases</a>.
-->

<p><a name="isin"><hr></a>
<h4>Whether type T is in parameter pack P:</h4>
<pre>
    template &lt;class T, class... P&gt; struct is_contained_in;

    template &lt;class T, class... P&gt;
      constexpr bool is_contained_in_v = is_contained_in&lt;T,P...&gt;::value;
</pre>
<h4>One possible implementation:</h4>
<pre>
    template &lt;class T&gt; struct is_contained_in&lt;T&gt; : false_type { };

    template &lt;class First, class... Rest&gt;
      struct is_contained_in&lt;First, First, Rest...&gt; : true_type { };

    template &lt;class T, class First, class... Rest&gt;
      struct is_contained_in&lt;T, First, Rest...&gt;
        : is_contained_in&lt;T, Rest...&gt; { };
</pre>
<hr>
<h4>
  Whether a <a href="#packer"><tt>packer</tt></a>, T, has a parameter pack that&rsquo;s
  a superset of the pack of some minimum <tt>packer</tt>, U:
</h4>
<pre>
    template &lt;class T, class U&gt; struct contains_types;

    template &lt;class T, class U&gt;
      constexpr bool contains_types_v = contains_types&lt;T,U&gt;::value;
</pre>
<h4>One possible implementation:</h4>
<pre>
    template &lt;class... TPack&gt;
      struct contains_types&lt;packer&lt;TPack...&gt;, packer&lt;&gt;&gt; : true_type { };

    template &lt;class... TPack, class UFirst, class... URest&gt;
      struct contains_types&lt;packer&lt;TPack...&gt;, packer&lt;UFirst, URest...&gt;&gt;
        : integral_constant&lt;bool,
            <a href="#isin">is_contained_in_v</a>&lt;UFirst, TPack...&gt; &amp;&amp;
            contains_types_v&lt;packer&lt;TPack...&gt;, packer&lt;URest...&gt;&gt;&gt; { };
</pre>
<hr>
<h4>
  Add type(s) to the end of what&rsquo;s probably, but not necessarily, a parameter pack:
</h4>
<pre>
    template&lt;class T, class U&gt; struct add_to;

    template&lt;class T, class U&gt;
      using add_to_t = typename add_to&lt;T,U&gt;::type;
</pre>
<h4>One possible implementation:</h4>

Note that <tt>T</tt> and <tt>U</tt> are permitted, but not required,
to be <tt>packer</tt>s.  It&rsquo;s not clear that <i>H. sapiens</i>
would need all those possibilities; but they&rsquo;re allowed for use
in machine-generated code.  This applies also to <tt>unique_add_to</tt>
and to <tt>remove_from</tt>&rsquo;s <tt>U</tt> parameter.

<pre>
    template&lt;class T, class U&gt;
    struct add_to&lt;T,U&gt;
    {
        typedef packer&lt;U,T&gt; type;  // note <a href="#atend">T added to the end</a>
    };

    template&lt;class T, class... Args&gt;
    struct add_to&lt;T, packer&lt;Args...&gt;&gt;
    {
        typedef packer&lt;Args..., T&gt; type;
    };

    template&lt;class... Args, class U&gt;
    struct add_to&lt;packer&lt;Args...&gt;, U&gt;
    {
        typedef packer&lt;U, Args...&gt; type;
    };

    template&lt;class... TArgs, class... UArgs&gt;
    struct add_to&lt;packer&lt;TArgs...&gt;, packer&lt;UArgs...&gt;&gt;
    {
        typedef packer&lt;UArgs..., TArgs...&gt; type;
    };
</pre>

<p><hr>
<h4>
  As above, but add the types only if they&rsquo;re not already present in <tt>U</tt>.
</h4>
<pre>
    template&lt;class T, class U&gt; struct unique_add_to;

    template&lt;class T, class U&gt;
      using unique_add_to_t = typename unique_add_to&lt;T,U&gt;::type;
</pre>
<h4>One possible implementation:</h4>
<pre>
    template&lt;class T, class U&gt; struct unique_add_to
    {
        typedef packer&lt;U,T&gt; type;
    };

    template&lt;class T&gt; struct unique_add_to&lt;T,T&gt;
    {
        typedef packer&lt;T&gt; type;
    };

    template&lt;class T, class... Args&gt;
    struct unique_add_to&lt;T, packer&lt;Args...&gt;&gt;
    {
        typedef conditional_t&lt;<a href="#isin">is_contained_in_v</a>&lt;T, Args...&gt;,
                              packer&lt;Args...&gt;,
                              packer&lt;Args..., T&gt;&gt; type;
    };

    template&lt;class... Args, class U&gt;
    struct unique_add_to&lt;packer&lt;Args...&gt;, U&gt;
    {
        typedef conditional_t&lt;<a href="#isin">is_contained_in_v</a>&lt;U, Args...&gt;,
                              packer&lt;Args...&gt;,
                              packer&lt;U, Args...&gt;&gt; type;
    };

    template&lt;class... Args&gt;
    struct unique_add_to&lt;packer&lt;Args...&gt;, packer&lt;Args...&gt;&gt;
    {
        typedef packer&lt;Args...&gt; type;
    };

    template&lt;class... Args&gt;
    struct unique_add_to&lt;packer&lt;&gt;, packer&lt;Args...&gt;&gt;
    {
        typedef packer&lt;Args...&gt; type;
    };

    <a name="atend">template&lt;class TFirst, class... TRest, class... UArgs&gt;</a>
    struct unique_add_to&lt;packer&lt;TFirst, TRest...&gt;, packer&lt;UArgs...&gt;&gt;
    {
        typedef conditional_t&lt;<a href="#isin">is_contained_in_v</a>&lt;TFirst, UArgs...&gt;,
                              unique_add_to&lt;packer&lt;TRest...&gt;, packer&lt;UArgs...&gt;&gt;,
                              unique_add_to&lt;packer&lt;TRest...&gt;, packer&lt;UArgs..., TFirst&gt;&gt;
                             &gt; type;
    };
</pre>
It&rsquo;s because of the recursion in <tt>unique_add_to</tt> when <tt>T</tt>
is itself a <tt>packer</tt> with a non-empty parameter pack that we specify
that the types be added at the end:  if they were added at the front,
their order would be reversed, which would likely be the greater surprise.

<p><hr>
<h4>
  Remove one or more types from a <tt>packer</tt>&rsquo;s parameter pack:
</h4>
<pre>
    template&lt;class Unwanted, class Given, class Result = packer&lt;&gt;&gt;
    struct remove_from;

    template&lt;class U, class G&gt;
      using remove_from_t = typename remove_from&lt;U,G&gt;::type;
</pre>
<h4>One possible implementation:</h4>
<pre>
    template&lt;class U, class... Out&gt;
    struct remove_from&lt;U, packer&lt;&gt;, packer&lt;Out...&gt;&gt;
    {
        typedef packer&lt;Out...&gt; type;
    };

    template&lt;class U, class GFirst, class... GRest, class... Out&gt;
    struct remove_from&lt;U, packer&lt;GFirst, GRest...&gt;, packer&lt;Out...&gt;&gt;
      : remove_from&lt;U,
                    packer&lt;GRest...&gt;,
                    conditional_t&lt;is_same_v&lt;GFirst, U&gt;,
                                  packer&lt;Out...&gt;,
                                  packer&lt;Out..., GFirst&gt;
                                 &gt;
                   &gt; { };

    template &lt;class... U, class GFirst, class... GRest, class... Out&gt;
    struct remove_from&lt;packer&lt;U...&gt;,
                       packer&lt;GFirst, GRest...&gt;,
                       packer&lt;Out...&gt;&gt;
      : remove_from&lt;packer&lt;U...&gt;,
                    packer&lt;GRest...&gt;,
                    conditional_t&lt;<a href="#isin">is_contained_in_v</a>&lt;GFirst, U...&gt;,
                                  packer&lt;Out...&gt;,
                                  packer&lt;Out..., GFirst&gt;
                                 &gt;
                   &gt; { };
</pre>

<a name="notp"><h4>Partly-baked idea:</h4></a>
Is is necessary to require that <tt>G</tt> be a <tt>packer</tt>?
<pre>
    template&lt;class U, class G&gt;
    struct remove_from&lt;U, G&gt;
    {
        typedef packer&lt;G&gt; type;
    };

    template&lt;class U&gt;
    struct remove_from&lt;U, U&gt;
    {
        typedef packer&lt;&gt; type;
    };
</pre>

<hr>
<h4>Remove duplicate types from a parameter pack:</h4>
<pre>
    template&lt;class T, class Result = packer&lt;&gt;&gt; struct uniqueify;

    template&lt;class T&gt; using uniqueify_t = typename uniqueify&lt;T&gt;::type;
</pre>
<h4>One possible implementation:</h4>
<pre>
    template&lt;class... Out&gt; struct uniqueify&lt;packer&lt;&gt;, packer&lt;Out...&gt;&gt;
    {
        typedef packer&lt;Out...&gt; type;
    };

    template&lt;class First, class... Rest, class... Out&gt;
    struct uniqueify&lt;packer&lt;First, Rest...&gt;, packer&lt;Out...&gt;&gt;
    {
        typedef conditional_t&lt;<a href="#isin">is_contained_in_v</a>&lt;First, Rest...&gt;,
                              uniqueify&lt;packer&lt;Rest...&gt;, packer&lt;Out...&gt;&gt;,
                              uniqueify&lt;packer&lt;Rest...&gt;, packer&lt;Out..., First&gt;&gt;
                             &gt; type;
    };
</pre>
Note that, given the above implementation, <tt>uniqueify</tt> removes the first of two duplicates;
so the order of the types in the resulting parameter pack
might be surprising.  For example,
<nobr><tt>uniqueify_t&lt;packer&lt;<i>one</i>,<i>two</i>,<i>one</i>&gt;&gt;</tt></nobr>
is <nobr><tt>packer&lt;<i>two</i>,<i>one</i>&gt;</tt>.</nobr>

<p><hr size=5>
<h3>
  Standardese relative to
  <a href="http://www.open-std.org/jtc1/sc22/wg21/prot/14882fdis/n3936.pdf">N3936</a>:
</h3>

In <b>20.10.2 Header <tt>&lt;type_traits&gt;</tt> synopsis</b> [meta.type.synop]:

<ul>
<li>Change &ldquo;// 20.10.3, <i>helper class:</i>&rdquo;
<ul>
<p><li>Make the heading plural:
<blockquote>
// 20.10.3, <i>helper class<ins>es</ins>:</i>
</blockquote>
<p><li>Add at the end:
<pre>
    <ins>template&lt;class... T&gt; struct packer;</ins>
</pre>
</ul>
</ul>
<table border=0><tr><td bgcolor=lightgrey>
Everything else in the paper is an addition even though it&rsquo;s not underlined.
</td></tr></table>
<ul>
<li>Add to &ldquo;// 20.10.6, <i>type relations:</i>&rdquo;
   (position and order at the discretion of the editor)
<pre>
    template &lt;class T, class... P&gt; struct is_contained_in;
    template &lt;class T, class U&gt; struct contains_types;

    template &lt;class T, class... P&gt;
      constexpr bool is_contained_in_v = is_contained_in&lt;T,P...&gt;::value;
    template &lt;class T, class U&gt;
      constexpr bool contains_types_v = contains_types&lt;T,U&gt;::value;
</pre>
<p><li>Add to &ldquo;// 20.10.7.6, <i>other transformations:</i>&rdquo;
   (position and order at the discretion of the editor)
<pre>
    template &lt;class T, class U&gt; struct add_to;
    template &lt;class T, class U&gt; struct unique_add_to;
    template &lt;class T, class U, class Result = packer&lt;&gt;&gt; struct remove_from;
    template &lt;class T, class Result = packer&lt;&gt;&gt; struct uniqueify;

    template &lt;class T, class U&gt;
      using add_to_t = typename add_to&lt;T,U&gt;::type;
    template &lt;class T, class U&gt;
      using unique_add_to_t = typename unique_add_to&lt;T,U&gt;::type;
    template &lt;class T, class U&gt;
      using remove_from_t = typename remove_from&lt;T,U&gt;::type;
    template &lt;class T&gt;
      using uniqueify_t = typename uniqueify&lt;T&gt;::type;
</pre>
</ul>

<hr>
<p>In <b>20.10.3 Helper classes</b> [meta.help]:
<ul>
<li>Add just before the closing brace of <tt>namespace</tt>&nbsp;<tt>std</tt>:
<pre>
    template&lt;class... T&gt; struct packer { };
</pre>
<p><li>Add a new paragraph after paragraph 1:
<blockquote>
The class template <tt>packer</tt> simply holds a parameter pack.
</blockquote>
</ul>

<hr>
<p>In <b>20.10.6 Relationships between types</b> [meta.rel], add to the end of Table 51:
<blockquote>
<table border>
<tr>
  <td>
    <tt>template &lt;class T, class... P&gt;<br>struct is_contained_in;</tt>
  </td>
  <td>
    Type <tt>T</tt> is contained<br>in
    parameter pack <tt>P</tt>
  </td>
  <td>&nbsp;</td>
</tr>
<tr>
  <td>
    <tt>template &lt;class T, class U&gt;<br>struct contains_types;</tt>
  </td>
  <td>
    <tt>T</tt>&rsquo;s parameter pack contains<br>at
    least one instance<br>of each of the types<br>in
    <tt>U</tt>&rsquo;s parameter pack
  </td>
  <td>
    <tt>T</tt> and <tt>U</tt> shall be <tt>packer</tt>s<br>(20.10.3).
  </td>
</tr>
</table>
</blockquote>

<a name="notdoneant"><hr></a>
<p>In <b>20.10.7.6 Other transformations</b> [meta.trans.other],<p>
<table border=0><tr><td bgcolor=lightgrey>
Some standardese for Table 57&rsquo;s Comments column remains to be written.
It depends on whether the <tt>U</tt> template parameters
are required to be <tt>packer</tt>s.  Also,
<a href="#notp">does <tt>remove_from</tt>&rsquo;s <tt>U</tt> parameter
need to be a <tt>packer</tt>?</a>
</td></tr></table>
<br>add to the end of Table 57:
<blockquote>
<table border>
<tr>
  <td>
    <tt>template &lt;class T, class U&gt;<br>struct add_to;</tt>
  </td>
  <td>&nbsp;</td>
  <td bgcolor=lightgrey>
    The member typedef <tt>type</tt> shall name<br>a
    <tt>packer</tt> whose parameter pack contains<br>
    [more to do]
  </td>
</tr>
<tr>
  <td>
    <tt>template &lt;class T, class U&gt;<br>struct unique_add_to;</tt>
  </td>
  <td>&nbsp;</td>
  <td bgcolor=lightgrey>
    The member typedef <tt>type</tt> shall name<br>a
    <tt>packer</tt> whose parameter pack contains<br>
    [more to do]
  </td>
</tr>
<tr>
  <td>
    <tt>template &lt;class T, class U,<br>&nbsp;&nbsp;class Result = packer&lt;&gt;&gt;<br>struct remove_from;</tt>
  </td>
  <td>
    <tt>U</tt> shall be a <tt>packer</tt> (20.10.3).
  </td>
  <td bgcolor=lightgrey>
    The member typedef <tt>type</tt> shall name<br>a
    <tt>packer</tt> whose parameter pack contains<br>each
    of the types in <tt>U</tt>&rsquo;s parameter pack<br>excluding
    the type <tt>T</tt>, or if <tt>T</tt> is itself a<br>
    <tt>packer</tt>, excluding any type in <tt>T</tt>&rsquo;s<br>parameter pack.
  </td>
</tr>
<tr>
  <td>
    <tt>template &lt;class U,<br>&nbsp;&nbsp;class Result = packer&lt;&gt;&gt;<br>struct uniqueify;</tt>
  </td>
  <td>
    <tt>U</tt> shall be a <tt>packer</tt> (20.10.3).
  </td>
  <td bgcolor=lightgrey>
    The member typedef <tt>type</tt> shall name<br>a
    <tt>packer</tt> whose parameter pack contains<br>each
    of the types in <tt>U</tt>&rsquo;s parameter pack<br>exactly
    once.  The order of the types in<br><tt>type</tt>&rsquo;s
    parameter pack is unspecified.
  </td>
</tr>
</table>
</blockquote>

<p><a name="appa"><hr size=5></a>
<h3>Appendix A, a crude test:</h3>

The actual code, in the public domain, can be found
<a href="http://www.cstdbill.com/ansi/cpp/packsearch/test-pack-manip.cpp">here</a>.

<pre>
#include &lt;iostream&gt;
#include &lt;type_traits&gt; // assume it has the additions proposed above
using namespace std;

//
// Some types to put in parameter packs:
//
struct one   { static const int value = 1; };
struct two   { static const int value = 2; };
struct three { static const int value = 3; };
struct four  { static const int value = 4; };
struct five  { static const int value = 5; };

typedef packer&lt;one, two, three&gt;   first_three;
typedef packer&lt;four, five&gt;        last_two;
typedef packer&lt;three, four, five&gt; last_three;

//
// Listing types on the standard output:
//
template&lt;class... Args&gt; void show_types(packer&lt;Args...&gt;);

template&lt;&gt; inline void show_types(packer&lt;&gt;) { }

template&lt;class First, class... Rest&gt;
void show_types(packer&lt;First, Rest...&gt;)
{
    cout &lt;&lt; First::value &lt;&lt; "  ";
    show_types(packer&lt;Rest...&gt;());
}

//
// The tests:
//
int main()
{
    cout &lt;&lt; boolalpha;

    cout &lt;&lt; contains_types&lt;first_three, packer&lt;&gt;&gt;::value &lt;&lt; '\n';
    cout &lt;&lt; contains_types&lt;first_three, packer&lt;one&gt;&gt;::value &lt;&lt; '\n';
    cout &lt;&lt; contains_types&lt;first_three, packer&lt;two&gt;&gt;::value &lt;&lt; '\n';
    cout &lt;&lt; contains_types&lt;first_three, packer&lt;three&gt;&gt;::value &lt;&lt; '\n';
    cout &lt;&lt; contains_types&lt;first_three, packer&lt;one,two&gt;&gt;::value &lt;&lt; '\n';
    cout &lt;&lt; contains_types&lt;first_three, packer&lt;one,three&gt;&gt;::value &lt;&lt; '\n';
    cout &lt;&lt; contains_types&lt;first_three, packer&lt;two,three&gt;&gt;::value &lt;&lt; '\n';
    cout &lt;&lt; contains_types&lt;first_three, first_three&gt;::value &lt;&lt; '\n';

    cout &lt;&lt; '\n';

    cout &lt;&lt; contains_types&lt;first_three, packer&lt;four&gt;&gt;::value &lt;&lt; '\n';
    cout &lt;&lt; contains_types&lt;first_three, last_two&gt;::value &lt;&lt; '\n';
    cout &lt;&lt; contains_types&lt;first_three, last_three&gt;::value &lt;&lt; '\n';
    cout &lt;&lt; contains_types&lt;packer&lt;one,two&gt;, first_three&gt;::value &lt;&lt; '\n';

    cout &lt;&lt; '\n';

    show_types(add_to&lt;three, first_three&gt;());
    cout &lt;&lt; '\n';
    show_types(add_to&lt;four, first_three&gt;());
    cout &lt;&lt; '\n';
    show_types(add_to&lt;last_two, first_three&gt;());
    cout &lt;&lt; '\n';
    show_types(add_to&lt;last_three, first_three&gt;());

    cout &lt;&lt; "\n\n";

    show_types(unique_add_to&lt;three, first_three&gt;());
    cout &lt;&lt; '\n';
    show_types(unique_add_to&lt;four, first_three&gt;());
    cout &lt;&lt; '\n';
    show_types(unique_add_to&lt;last_two, first_three&gt;());
    cout &lt;&lt; '\n';
    show_types(unique_add_to&lt;last_three, first_three&gt;());

    cout &lt;&lt; "\n\n";

    show_types(remove_from&lt;one, first_three&gt;::type());
    cout &lt;&lt; '\n';
    show_types(remove_from&lt;two, first_three&gt;::type());
    cout &lt;&lt; '\n';
    show_types(remove_from&lt;three, first_three&gt;::type());
    cout &lt;&lt; '\n';
    show_types(remove_from&lt;four, first_three&gt;::type());
    cout &lt;&lt; '\n';
    show_types(remove_from&lt;last_two, first_three&gt;::type());
    cout &lt;&lt; '\n';
    show_types(remove_from&lt;last_three, first_three&gt;::type());


    cout &lt;&lt; "\n\n";

    show_types(uniqueify&lt;first_three&gt;::type());
    cout &lt;&lt; '\n';
    show_types(uniqueify&lt;packer&lt;one, two, one&gt;&gt;::type());
    cout &lt;&lt; '\n';
    show_types(
      uniqueify&lt;packer&lt;one, one, two, three, four, two, four, four&gt;&gt;::type());
}
</pre>
<h4>Expected output:</h4>
<pre>
true
true
true
true
true
true
true
true

false
false
false
false

1  2  3  3
1  2  3  4
1  2  3  4  5
1  2  3  3  4  5

1  2  3
1  2  3  4
1  2  3  4  5
1  2  3  4  5

2  3
1  3
1  2
1  2  3
1  2  3
1  2

1  2  3
2  1
1  3  2  4
</pre>

<p><hr size=5>
<b>Reply to:</b>&nbsp;&nbsp;<tt>stdbill.h@pobox.com</tt>
</body>
</html>
