    <rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:admin="http://webns.net/mvcb/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:content="http://purl.org/rss/1.0/modules/content/">
     <channel>
        <title>ACCU  :: Getting Tuple Elements with a Runtime Index</title>
        <link>https://members.accu.org/index.php/articles/2382</link>
        <description>Professionalism in Programming</description>
        <dc:language>en-us</dc:language> 
        <dc:creator>Administrator</dc:creator> 
        <admin:generatorAgent rdf:resource="http://www.xaraya.org" /> 
        <admin:errorReportsTo rdf:resource="mailto:webeditor@accu.org" />
       <sy:updatePeriod>hourly</sy:updatePeriod>
       <sy:updateFrequency>1</sy:updateFrequency>
       <docs>http://backend.userland.com/rss</docs>




<div class="xar-mod-head"><span class="xar-mod-title">Programming Topics + Overload Journal #139 - June 2017</span></div>

<table border="0" cellpadding="1" cellspacing="0">
    <tbody>
    <tr>
        <td valign="top">
            Browse in :
       </td>
       <td valign="top">

                                            <a href="https://members.accu.org/index.php/articles/">All</a>

                     &gt;                         <a href="https://members.accu.org/index.php/articles/c13/">Topics</a>

                     &gt;                         <a href="https://members.accu.org/index.php/articles/c65/">Programming</a>
<br />

                                            <a href="https://members.accu.org/index.php/articles/">All</a>

                     &gt;                         <a href="https://members.accu.org/index.php/articles/c76/">Journals</a>

                     &gt;                         <a href="https://members.accu.org/index.php/articles/c78/">Overload</a>

                     &gt;                         <a href="https://members.accu.org/index.php/articles/c374/">o139</a>
<br />

                                            <a href="https://members.accu.org/index.php/articles/c65-374/">Any of these categories</a>

                    -                        <a href="https://members.accu.org/index.php/articles/c65+374/">All of these categories</a>
<br />
</td>
   </tr>
   </tbody>
</table>




<div class="xar-error">
   <p>
 <strong>Note:</strong> when you create a new publication type,
the articles module will automatically use the templates
<em>user-display-[publicationtype].xt</em>
and <em>user-summary-[publicationtype].xt</em>.
If those templates do not exist when you try to preview or display a new article,
you'll get this warning :-)  Please place your own templates in themes/<em>yourtheme</em>/modules/articles . The templates will get the extension .xt there. </p>
</div>
<div class="xar-norm xar-standard-box-padding">
   <h1><strong>Title:</strong>&nbsp;Getting Tuple Elements with a Runtime Index</h1>
<p><strong>Author:</strong>&nbsp;Martin Moene</p>
<p>
<strong>Date:</strong> 02 June 2017 13:32:06 +01:00 or Fri, 02 June 2017 13:32:06 +01:00</p>
<p><strong>Summary:</strong>&nbsp;Accessing a tuple with a runtime index is a challenge. Anthony Williams shows us his approach.</p>
<p><strong>Body:</strong>&nbsp;<p><code>std::tuple</code> is great. It provides a nice, generic way of holding a fixed-size set of data items of whatever types you need. However, sometimes it has limitations that mean it doesnâ€™t quite work as youâ€™d like. One of these is accessing an item based on a <em>runtime</em> index.</p>

<h2>std::get needs a compile-time index</h2>

<p>The way to get the nth item in a tuple is to use <code>std::get: std::get&lt;n&gt;(my_tuple)</code>. This works nicely, as long as <code>n</code> is a compile-time constant. If youâ€™ve got a value that is calculated at runtime, this doesnâ€™t work: you canâ€™t use a value that isn't known until runtime as a template parameter.</p>

<pre class="programlisting">
  std::tuple&lt;int,int,int&gt; my_tuple=...;
  size_t index;
  std::cin&gt;&gt;index;
  int val=std::get&lt;index&gt;(my_tuple); //won't compile</pre>

<p>So, what can we do? We need a new function, which Iâ€™ll call <code>runtime_get</code>, to retrieve the <code>n</code>th value, where <code>n</code> is a runtime value.</p>

<pre class="programlisting">
  template&lt;typename Tuple&gt;
  ... runtime_get(Tuple&amp;&amp; t,size_t index){
    ...
  }</pre>

<p>The question is: how do we implement it?</p>

<h2>Fixed return type</h2>

<p>The return type is easy: our function must have a single return type for any given <code>Tuple</code>. That means that all the elements in the tuple must have the same type, so we can just use the type of the first element. <code>std::tuple_element</code> will tell us this, though we must first adjust our template parameter so itâ€™s not a reference.</p>

<pre class="programlisting">
  template&lt;typename Tuple&gt;
  typename std::tuple_element&lt;
   0, typename std::remove_reference&lt;Tuple&gt;
   ::type&gt;::type&amp;
  runtime_get(Tuple&amp;&amp; t,size_t index){
    ...
  }</pre>

<p>Note: C++17 includes <code>std::variant</code>, so you might think we could use that to hold the return type, but that wouldnâ€™t actually help us: to get the value from a variant, you need to call <code>std::get&lt;n&gt;(v)</code>, which requires <code>n</code> to be a constant (again)!</p>

<p>OK, so the return type is just a reference to the type of the first element. How do we get the element?</p>

<h2>Retrieving the nth element</h2>

<p>We canâ€™t do a straightforward <code>switch</code>, because that requires knowing all the cases in advance, and we want this to work for any size of tuple.</p>

<p>One way would be to have a recursive function that checked the runtime index against a compile-time index, and then called the function with the next compile-time index if they were different, but that would mean that the access time would depend on the index, and potentially end up with a deeply nested function call if we wanted the last element in a large tuple.</p>

<p>One thing we <em>can</em> do is use the index value as an array index. If we have an array of functions, each of which returns the corresponding element from the tuple, then we can call the appropriate function to return the relevant index.</p>

<p>The function we need is of course <code>std::get</code>; itâ€™s just a matter of getting the function signature right. Our overload of <code>std::get</code> has the following signature for <code>const</code> and non-<code>const</code> tuples:</p>

<pre class="programlisting">
  template &lt;size_t I, class... Types&gt;
  constexpr tuple_element_t&lt;I, tuple&lt;Types...&gt;&gt;&amp;
  get(tuple&lt;Types...&gt;&amp;) noexcept;
  template &lt;size_t I, class... Types&gt;
  constexpr const tuple_element_t&lt;I,
    tuple&lt;Types...&gt;&gt;&amp;
  get(const tuple&lt;Types...&gt;&amp;) noexcept;</pre>

<p>so, we can capture the relevant instantiation of <code>std::get</code> for a given tuple type <code>Tuple</code> in a function pointer declared as:</p>

<pre class="programlisting">
  using return_type=typename
    std::tuple_element&lt;0,Tuple&gt;::type&amp;;
  using get_func_ptr=return_type(*)(Tuple&amp;)
    noexcept;</pre>

<p>The signature is the same, regardless of the index, because we made the decision that weâ€™re only going to support tuples where all the elements are the same.</p>

<p>This makes it easy to build a function table: use a variadic pack expansion to supply a different index for each array element, and fill in <code>std::get&lt;N&gt; </code>for each entry (see Listing 1).</p>

<table class="sidebartable">
	<tr>
		<td>
			<pre class="programlisting">
template&lt;
    typename Tuple,
    typename Indices=std::make_index_sequence&lt;std::tuple_size&lt;Tuple&gt;::value&gt;&gt;
struct runtime_get_func_table;

template&lt;typename Tuple,size_t ... Indices&gt;
    struct runtime_get_func_table&lt;Tuple,std::index_sequence&lt;Indices...&gt;&gt;{
    using return_type=typename std::tuple_element&lt;0,Tuple&gt;::type&amp;;
    using get_func_ptr=return_type (*)(Tuple&amp;) noexcept;
    static constexpr get_func_ptr table[std::tuple_size&lt;Tuple&gt;::value]={
        &amp;std::get&lt;Indices&gt;...
    };
};

template&lt;typename Tuple,size_t ... Indices&gt;
constexpr typename
runtime_get_func_table&lt;Tuple,std::index_sequence&lt;Indices...&gt;&gt;::get_func_ptr
runtime_get_func_table&lt;Tuple,std::index_sequence&lt;Indices...&gt;&gt;::table[
    std::tuple_size&lt;Tuple&gt;::value];			</pre>
		</td>
	</tr>
	<tr>
		<td class="title">Listing 1</td>
	</tr>
</table>
<p>We need the separate redeclaration of the table to satisfy a pre-C++17 compiler; with C++17 inline variables it is no longer needed.</p>

<p>Our final function is then just a simple wrapper around a table lookup (see Lising 2).</p>

<table class="sidebartable">
	<tr>
		<td>
			<pre class="programlisting">
template&lt;typename Tuple&gt;
constexpr
typename std::tuple_element&lt;0,typename std::remove_reference&lt;Tuple&gt;::type&gt;::type&amp;
runtime_get(Tuple&amp;&amp; t,size_t index){
    using tuple_type=typename std::remove_reference&lt;Tuple&gt;::type;
    if(index&gt;=std::tuple_size&lt;tuple_type&gt;::value)
        throw std::runtime_error(&quot;Out of range&quot;);
    return runtime_get_func_table&lt;tuple_type&gt;::table[index](t);
}			</pre>
		</td>
	</tr>
	<tr>
		<td class="title">Listing 2</td>
	</tr>
</table>

<p>Itâ€™s <code>constexpr</code> safe, though in a <code>constexpr</code> context you could probably just use <code>std::get</code> directly anyway.</p>

<p>So, there you have it: a constant-time function for retrieving the <code>n</code>th element of a tuple where all the elements have the same type.</p>

<h2>Final code</h2>

<p>Listing 3 is the final code for a constant-time function to retrieve an item from a tuple based on a runtime index.</p>

<table class="sidebartable">
	<tr>
		<td>
			<pre class="programlisting">
#include &lt;tuple&gt;
#include &lt;utility&gt;
#include &lt;type_traits&gt;
#include &lt;stdexcept&gt;

template&lt;
    typename Tuple,
    typename Indices=std::make_index_sequence&lt;std::tuple_size&lt;Tuple&gt;::value&gt;&gt;
struct runtime_get_func_table;

template&lt;typename Tuple,size_t ... Indices&gt;
struct runtime_get_func_table&lt;Tuple,std::index_sequence&lt;Indices...&gt;&gt;{
    using return_type=typename std::tuple_element&lt;0,Tuple&gt;::type&amp;;
    using get_func_ptr=return_type (*)(Tuple&amp;) noexcept;
    static constexpr get_func_ptr table[std::tuple_size&lt;Tuple&gt;::value]={
        &amp;std::get&lt;Indices&gt;...
    };
};

template&lt;typename Tuple,size_t ... Indices&gt;
constexpr typename
runtime_get_func_table&lt;Tuple,std::index_sequence&lt;Indices...&gt;&gt;::get_func_ptr
runtime_get_func_table&lt;Tuple,std::index_sequence&lt;Indices...&gt;&gt;::table[std::tuple_size&lt;Tuple&gt;::value];

template&lt;typename Tuple&gt;
constexpr
typename std::tuple_element&lt;0,typename std::remove_reference&lt;Tuple&gt;::type&gt;::type&amp;
runtime_get(Tuple&amp;&amp; t,size_t index){
    using tuple_type=typename std::remove_reference&lt;Tuple&gt;::type;
    if(index&gt;=std::tuple_size&lt;tuple_type&gt;::value)
        throw std::runtime_error(&quot;Out of range&quot;);
    return runtime_get_func_table&lt;tuple_type&gt;::table[index](t);
}			</pre>
		</td>
	</tr>
	<tr>
		<td class="title">Listing 3</td>
	</tr>
</table>
</p>
<p><strong>Notes:</strong>&nbsp;</p>
<p><em>More fields may be available via dynamicdata ..</em></p>
</div>
</channel>
</rss>
