<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[flatten_t&amp;lt;&amp;gt; in O(1)?]]></title><description><![CDATA[<p>Ich suche die Effizienteste (nach Rekursionstiefe) Implementierung für folgende Metafunktion:</p>
<pre><code>using tup = std::tuple &lt;int, float, std::tuple &lt;double, char&gt;, long&gt;;
using flat = flatten_t &lt;tup&gt;; // -&gt; std::tuple &lt;int, float, double, char, long&gt;
</code></pre>
<p>meine pseudo lösung in O(n) [Rekursionstiefe].<br />
EDIT: (mein if ist lazy)<br />
EDIT: Die Pseudolösung nimmt auch kein tuple, sondern args. Aber das ist egal.</p>
<pre><code>template &lt;typename T, typename... List&gt;
struct flatten {
    using type = 
    if_ &lt;is_tuple &lt;T&gt;::value, /* do merge with recursive flatten::type O(1) */, 
                              /* push_back / push_front with recursive flatten::type O(1) */&gt;::type; 
};

template &lt;typename T&gt;
struct flatten &lt;T&gt; {
    using type = 
    if_ &lt;is_tuple &lt;T&gt;::value, T, 
                              std::tuple &lt;T&gt; &gt;::type
};
</code></pre>
<p>Ist das auch in konstanter Rekursionstiefe machbar?</p>
<p>EDIT: Das ist die tatsächliche Implementierung, aber da die eh niemand ausprobieren kann...</p>
<pre><code>// fundamental
#include &quot;../fundamental/eval_if.hpp&quot;

// control
#include &quot;../control/if.hpp&quot;

// tuple
#include &quot;../tuple/is_tuple.hpp&quot;
#include &quot;../tuple/concat.hpp&quot;
#include &quot;../tuple/apply.hpp&quot;

// algorithm
#include &quot;merge.hpp&quot;

// functional
#include &quot;../functional/lift.hpp&quot;

namespace mplex
{
    namespace internal {
        struct flatten_impl;

        struct flatten_impl {
            template &lt;typename Head, typename... Tail&gt;
            struct apply
            {
                using _is_tuple = typename is_tuple::template apply &lt;Head&gt;::type;
                using _is_not_tuple = bool_ &lt;!_is_tuple::value&gt;;

                using type = lazy_if_t &lt;_is_tuple,
                                        then_ &lt;lift&lt;concat&gt;, Head, eval_if_default_t &lt;_is_tuple, std::tuple&lt;&gt;, flatten_impl, Tail...&gt;&gt;,
                                        else_ &lt;lift&lt;push_front&gt;, eval_if_default_t &lt;_is_not_tuple, std::tuple&lt;&gt;, flatten_impl, Tail...&gt;, Head&gt;&gt;;
            };

        };

        template &lt;typename Head&gt;
        struct flatten_impl::apply &lt;Head&gt; {
            using type = if_t &lt;typename is_tuple::template apply &lt;Head&gt;::type,
                               Head, std::tuple &lt;Head&gt;&gt;;
        };
    }

    /**
     *  Flattens a tuple, but not deep.
     *
     *  std::tuple&lt;int, float, std::tuple &lt;char, long&gt;, double&gt;
     *  becomes std::tuple&lt;int, float, char, long, double&gt;
     *
     */
    template &lt;typename Tuple&gt;
    struct flatten {
        using type = typename apply_t &lt;Tuple, internal::flatten_impl::template apply&gt;::type;
    };

    template &lt;typename Tuple&gt;
    using flatten_t = typename flatten &lt;Tuple&gt;::type;
}
</code></pre>
]]></description><link>https://www.c-plusplus.net/forum/topic/335560/flatten_t-lt-gt-in-o-1</link><generator>RSS for Node</generator><lastBuildDate>Fri, 24 Apr 2026 10:13:53 GMT</lastBuildDate><atom:link href="https://www.c-plusplus.net/forum/topic/335560.rss" rel="self" type="application/rss+xml"/><pubDate>Thu, 26 Nov 2015 19:20:00 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to flatten_t&amp;lt;&amp;gt; in O(1)? on Thu, 26 Nov 2015 20:34:53 GMT]]></title><description><![CDATA[<p>Ich suche die Effizienteste (nach Rekursionstiefe) Implementierung für folgende Metafunktion:</p>
<pre><code>using tup = std::tuple &lt;int, float, std::tuple &lt;double, char&gt;, long&gt;;
using flat = flatten_t &lt;tup&gt;; // -&gt; std::tuple &lt;int, float, double, char, long&gt;
</code></pre>
<p>meine pseudo lösung in O(n) [Rekursionstiefe].<br />
EDIT: (mein if ist lazy)<br />
EDIT: Die Pseudolösung nimmt auch kein tuple, sondern args. Aber das ist egal.</p>
<pre><code>template &lt;typename T, typename... List&gt;
struct flatten {
    using type = 
    if_ &lt;is_tuple &lt;T&gt;::value, /* do merge with recursive flatten::type O(1) */, 
                              /* push_back / push_front with recursive flatten::type O(1) */&gt;::type; 
};

template &lt;typename T&gt;
struct flatten &lt;T&gt; {
    using type = 
    if_ &lt;is_tuple &lt;T&gt;::value, T, 
                              std::tuple &lt;T&gt; &gt;::type
};
</code></pre>
<p>Ist das auch in konstanter Rekursionstiefe machbar?</p>
<p>EDIT: Das ist die tatsächliche Implementierung, aber da die eh niemand ausprobieren kann...</p>
<pre><code>// fundamental
#include &quot;../fundamental/eval_if.hpp&quot;

// control
#include &quot;../control/if.hpp&quot;

// tuple
#include &quot;../tuple/is_tuple.hpp&quot;
#include &quot;../tuple/concat.hpp&quot;
#include &quot;../tuple/apply.hpp&quot;

// algorithm
#include &quot;merge.hpp&quot;

// functional
#include &quot;../functional/lift.hpp&quot;

namespace mplex
{
    namespace internal {
        struct flatten_impl;

        struct flatten_impl {
            template &lt;typename Head, typename... Tail&gt;
            struct apply
            {
                using _is_tuple = typename is_tuple::template apply &lt;Head&gt;::type;
                using _is_not_tuple = bool_ &lt;!_is_tuple::value&gt;;

                using type = lazy_if_t &lt;_is_tuple,
                                        then_ &lt;lift&lt;concat&gt;, Head, eval_if_default_t &lt;_is_tuple, std::tuple&lt;&gt;, flatten_impl, Tail...&gt;&gt;,
                                        else_ &lt;lift&lt;push_front&gt;, eval_if_default_t &lt;_is_not_tuple, std::tuple&lt;&gt;, flatten_impl, Tail...&gt;, Head&gt;&gt;;
            };

        };

        template &lt;typename Head&gt;
        struct flatten_impl::apply &lt;Head&gt; {
            using type = if_t &lt;typename is_tuple::template apply &lt;Head&gt;::type,
                               Head, std::tuple &lt;Head&gt;&gt;;
        };
    }

    /**
     *  Flattens a tuple, but not deep.
     *
     *  std::tuple&lt;int, float, std::tuple &lt;char, long&gt;, double&gt;
     *  becomes std::tuple&lt;int, float, char, long, double&gt;
     *
     */
    template &lt;typename Tuple&gt;
    struct flatten {
        using type = typename apply_t &lt;Tuple, internal::flatten_impl::template apply&gt;::type;
    };

    template &lt;typename Tuple&gt;
    using flatten_t = typename flatten &lt;Tuple&gt;::type;
}
</code></pre>
]]></description><link>https://www.c-plusplus.net/forum/post/2477215</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2477215</guid><dc:creator><![CDATA[5cript]]></dc:creator><pubDate>Thu, 26 Nov 2015 20:34:53 GMT</pubDate></item><item><title><![CDATA[Reply to flatten_t&amp;lt;&amp;gt; in O(1)? on Thu, 26 Nov 2015 21:23:29 GMT]]></title><description><![CDATA[<p>Man kann logarithmische Tiefe erreichen. Ich denke, folgendes funktioniert - nur schnell heruntergetippt, geht wahrscheinlich viel eleganter (und effizienter):</p>
<pre><code>#include &lt;type_traits&gt;

template &lt;typename T&gt; struct identity {using type=T;};

template &lt;std::size_t ... args&gt;
struct index_list {using type=index_list;};

template &lt;typename T&gt; using eval = typename T::type;

template &lt;typename...&gt; struct pack {};

template &lt;typename&gt; constexpr std::size_t length=0;
template &lt;typename... xs&gt;
constexpr auto length&lt;pack&lt;xs...&gt;&gt; = sizeof...(xs);

template &lt;typename, typename&gt; struct duplicate;
template &lt;std::size_t... is, std::size_t... ts&gt;
struct duplicate&lt;index_list&lt;is...&gt;, index_list&lt;ts...&gt;&gt; : index_list&lt;is..., (sizeof...(is)+is)...,
                                                                         (2*sizeof...(is)+ts)...&gt; {};

template &lt;std::size_t N&gt;
struct make_index_list :
	duplicate&lt; eval&lt;make_index_list&lt;N/2&gt;&gt;,
	           eval&lt;make_index_list&lt;N%2&gt;&gt; &gt; {};

template &lt;&gt; struct make_index_list&lt;1&gt; : index_list&lt;0&gt; {};
template &lt;&gt; struct make_index_list&lt;0&gt; : index_list&lt;&gt; {};

template &lt;std::size_t N&gt;
using make_index_list_t = eval&lt;make_index_list&lt;N&gt;&gt;;

/// ////////////////////////////////////////////////////////////////////////////////////////

template &lt;typename T, std::size_t&gt;
struct type_node {using type=T;};
template &lt;std::size_t I, typename U&gt;
identity&lt;U&gt; type_deducer(type_node&lt;U,I&gt;);

template &lt;typename P, typename=make_index_list_t&lt;length&lt;P&gt;&gt;&gt;
struct type_map;
template &lt;typename... T, std::size_t... indices&gt;
struct type_map&lt;pack&lt;T...&gt;, index_list&lt;indices...&gt;&gt; : type_node&lt;T, indices&gt;... {};

template &lt;typename M, std::size_t I&gt;
using get_t = eval&lt;decltype(type_deducer&lt;I&gt;(M()))&gt;;

/// ////////////////////////////////////////////////////////////////////////////////////////

template &lt;typename, typename&gt; struct cat;
template &lt;typename... ls, typename... rs&gt;
struct cat&lt;pack&lt;ls...&gt;, pack&lt;rs...&gt;&gt; {using type=pack&lt;ls...,rs...&gt;;};
template &lt;typename A, typename B&gt; using cat_t = eval&lt;cat&lt;A,B&gt;&gt;;

template &lt;typename P, std::size_t I=0, std::size_t L=length&lt;P&gt;&gt;
struct flatten : cat&lt;typename flatten&lt;P, I, L/2&gt;::type, typename flatten&lt;P, I+L/2, L/2 + L%2&gt;::type&gt; {};
template &lt;typename P, std::size_t I&gt;
struct flatten&lt;P, I, 1&gt; {
	template &lt;typename _&gt; struct aux {using type=pack&lt;_&gt;;};
	template &lt;typename... _&gt;
	struct aux&lt;pack&lt;_...&gt;&gt; : flatten&lt;pack&lt;_...&gt;&gt; {};

	using type = typename aux&lt;typename decltype(type_deducer&lt;I&gt;(type_map&lt;P&gt;()))::type&gt;::type;
};
template &lt;&gt; struct flatten&lt;pack&lt;&gt;, 0, 0&gt; {using type=pack&lt;&gt;;};

template &lt;typename P&gt;
using flatten_t = eval&lt;flatten&lt;P&gt;&gt;;

static_assert(std::is_same&lt;flatten_t&lt;pack&lt;int, float, pack&lt;double, pack&lt;long&gt;&gt;, pack&lt;int&gt;&gt;&gt;,
                                     pack&lt;int, float, double, long, int&gt;&gt;{});
</code></pre>
]]></description><link>https://www.c-plusplus.net/forum/post/2477227</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2477227</guid><dc:creator><![CDATA[Columbo]]></dc:creator><pubDate>Thu, 26 Nov 2015 21:23:29 GMT</pubDate></item><item><title><![CDATA[Reply to flatten_t&amp;lt;&amp;gt; in O(1)? on Thu, 26 Nov 2015 21:09:35 GMT]]></title><description><![CDATA[<ol>
<li>
<p>Ich wusste du würdest antworten <img
      src="https://www.c-plusplus.net/forum/plugins/nodebb-plugin-emoji/emoji/emoji-one/1f609.png?v=ab1pehoraso"
      class="not-responsive emoji emoji-emoji-one emoji--winking_face"
      title=";)"
      alt="😉"
    /></p>
</li>
<li>
<p>Erster Eindruck: Holy ****</p>
</li>
<li></li>
</ol>
<pre><code>template &lt;typename T&gt; using eval = typename T::type;
</code></pre>
<p>Ist das eine Denksache?</p>
<ol start="4">
<li></li>
</ol>
<pre><code>template &lt;typename...&gt; struct pack {};
</code></pre>
<p>Ich muss auch nochmal umstellen.</p>
<ol start="5">
<li>Ich brauche glaube ich noch ein bisschen Zeit, bis ich den Code komplett verstanden habe ^^.</li>
</ol>
<p>EDIT: ah, das ist viel hilfcode und nicht so viel zum eigentlichen problem.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2477233</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2477233</guid><dc:creator><![CDATA[5cript]]></dc:creator><pubDate>Thu, 26 Nov 2015 21:09:35 GMT</pubDate></item><item><title><![CDATA[Reply to flatten_t&amp;lt;&amp;gt; in O(1)? on Thu, 26 Nov 2015 21:41:13 GMT]]></title><description><![CDATA[<p>Habe den Code nochmal angepasst. Hilft aber alles nix. Läuft nämlich linear in der Länge der resultierenden Liste.</p>
<pre><code>template &lt;int N&gt;
struct construct {using type=pack&lt;int, double, float, char, bool, long, typename construct&lt;N-1&gt;::type&gt;;};
template &lt;&gt;
struct construct&lt;0&gt; {using type=pack&lt;&gt;;};

using F = flatten_t&lt;construct&lt;64&gt;::type&gt;;
</code></pre>
<p>Packen GCC und Clang in genau 322 Instantiierungen, wobei die resultierende Liste aber 384 ist.<br />
<code>flatten_t&lt;construct&lt;128&gt;::type&gt;</code> braucht exakt 643 Instantiierungen für eine doppelt so lange Liste.</p>
<p>Sorry, hab' mich nicht richtig mit dem Problem auseinandergesetzt. Habe ein paar Ideen, die ich mir anschauen werde.</p>
<blockquote>
<p>Ich muss auch nochmal umstellen.</p>
</blockquote>
<p><code>pack</code> kompiliert deutlich schneller als <code>tuple</code> . Siehe e.g. <a href="http://stackoverflow.com/a/26456742/3647361" rel="nofollow">hier</a>, wo das verwenden von <code>pack</code> die Effizienz krass gesteigert hat.</p>
<blockquote>
<p>ah, das ist viel hilfcode und nicht so viel zum eigentlichen problem.</p>
</blockquote>
<p>Ja, ich wollte nämlich logarithmische Instantiierungstiefe für <code>make_index_list</code> , was Implementierungen von <code>std::make_index_sequence</code> in libc++ und libstdc++ momentan nicht vorzeigen können.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2477237</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2477237</guid><dc:creator><![CDATA[Columbo]]></dc:creator><pubDate>Thu, 26 Nov 2015 21:41:13 GMT</pubDate></item><item><title><![CDATA[Reply to flatten_t&amp;lt;&amp;gt; in O(1)? on Thu, 26 Nov 2015 22:13:29 GMT]]></title><description><![CDATA[<blockquote>
<p>Packen GCC und Clang in genau 322 Instantiierungen, wobei die resultierende Liste aber 384 ist.<br />
flatten_t&lt;construct&lt;128&gt;::type&gt; braucht exakt 643 Instantiierungen für eine doppelt so lange Liste.</p>
</blockquote>
<p>Wie weißt du das so genau?</p>
<pre><code>pack kompiliert deutlich schneller als tuple. Siehe e.g. hier, wo das verwenden von pack die Effizienz krass gesteigert hat.
</code></pre>
<p>Ja das habe ich vor ein paar Wochen gehört, vom boost Hana Schöpfer (in einem seiner talks).</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2477238</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2477238</guid><dc:creator><![CDATA[5cript]]></dc:creator><pubDate>Thu, 26 Nov 2015 22:13:29 GMT</pubDate></item><item><title><![CDATA[Reply to flatten_t&amp;lt;&amp;gt; in O(1)? on Thu, 26 Nov 2015 22:16:55 GMT]]></title><description><![CDATA[<p>Habe mich vertan, es scheint, dass pro Schachtelungstiefe ein logarithmischer Overhead besteht. Hier wohl 5 - einer für <code>aux</code> , ein anderer für die Spezialisierung von <code>type_deducer</code> um auf den Typ zuzugreifen, und <span class="katex"><span class="katex-mathml"><math><semantics><mrow><mo>⌈</mo><mtext><mi mathvariant="normal">l</mi><mi mathvariant="normal">b</mi></mtext><mn>7</mn><mo>⌉</mo></mrow><annotation encoding="application/x-tex">\lceil \text{lb} 7 \rceil</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="strut" style="height:0.75em;"></span><span class="strut bottom" style="height:1em;vertical-align:-0.25em;"></span><span class="base textstyle uncramped"><span class="mopen">⌈</span><span class="text mord textstyle uncramped"><span class="mord mathrm">l</span><span class="mord mathrm">b</span></span><span class="mord mathrm">7</span><span class="mclose">⌉</span></span></span></span>. Daher 5*128 = 640, plus drei Instantiierungen drum herum. Das scheint im Nachhinein von der Komplexität ziemlich optimal zu sein, schließlich brauchen wir auf jeder Ebene auch mindestens einen logarithmischen Overhead zum konkatenieren.</p>
<p>Eine Idee wäre zumindest, nur Indizen auf die packs zu speichern, diese dann parallel(!!!) zu flatten und anschließend die Konkatenierung der resultierenden packs und der ursprünglichen, nicht-pack Typen rekursiv vorzunehmen. Das werd' ich mir mal anschauen.</p>
<p>5cript schrieb:</p>
<blockquote>
<p>Woher weißt du das so genau?</p>
</blockquote>
<p>Du kannst eine Intervall schachtelnde Bash-Anweisung schreiben, die den Rückgabewert des Compilers als Vergleichsprädikat nimmt (1 =&gt; kleiner, 0 &lt;= größer) und das Argument an <code>-ftemplate-depth</code> anpasst.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2477242</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2477242</guid><dc:creator><![CDATA[Columbo]]></dc:creator><pubDate>Thu, 26 Nov 2015 22:16:55 GMT</pubDate></item><item><title><![CDATA[Reply to flatten_t&amp;lt;&amp;gt; in O(1)? on Thu, 26 Nov 2015 22:29:24 GMT]]></title><description><![CDATA[<blockquote>
<p>Du kannst eine Intervall schachtelnde Bash-Anweisung schreiben, die den Rückgabewert des Compilers als Vergleichsprädikat nimmt (1 =&gt; kleiner, 0 &lt;= größer) und das Argument an -ftemplate-depth anpasst.</p>
</blockquote>
<p>smart!</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2477243</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2477243</guid><dc:creator><![CDATA[5cript]]></dc:creator><pubDate>Thu, 26 Nov 2015 22:29:24 GMT</pubDate></item><item><title><![CDATA[Reply to flatten_t&amp;lt;&amp;gt; in O(1)? on Fri, 27 Nov 2015 10:35:14 GMT]]></title><description><![CDATA[<p>Ja, meine Idee hat sehr geholfen. <code>construct&lt;64&gt;</code> braucht kaum mehr 76 Instantiierungen, <code>construct&lt;128&gt;</code> 140. Die Linearität in der Verschachtelungstiefe hat sich natürlich nicht geändert (immer noch <span class="katex"><span class="katex-mathml"><math><semantics><mrow><mi mathvariant="normal">Θ</mi><mo>(</mo><mi>n</mi><mo>)</mo></mrow><annotation encoding="application/x-tex">\Theta(n)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="strut" style="height:0.75em;"></span><span class="strut bottom" style="height:1em;vertical-align:-0.25em;"></span><span class="base textstyle uncramped"><span class="mord mathrm">Θ</span><span class="mopen">(</span><span class="mord mathit">n</span><span class="mclose">)</span></span></span></span>), was sich auch nicht ändern kann, aber wir haben nun einen Overhead, der logarithmisch in der Länge des längsten, rekursiv enthaltenen Packs wächst. I.e. wenn jedes pack in construct&lt;64&gt; stattdessen 32 Member hat, bekommen wir 78, was natürlich bei zwei zusätzlichen (binären) Größenordnungen über 8 ziemlich einleuchtend ist.</p>
<pre><code>#include &lt;type_traits&gt;

template &lt;typename T&gt; struct identity {using type=T;};

template &lt;std::size_t... args&gt;
struct index_list{
	using type=index_list;
	static constexpr std::size_t arr[] = {args...};
};

template &lt;typename T&gt; using eval = typename T::type;

template &lt;typename...&gt; struct pack {using type=pack;};

template &lt;typename&gt; constexpr std::size_t length=0;
template &lt;typename... xs&gt;
constexpr auto length&lt;pack&lt;xs...&gt;&gt; = sizeof...(xs);

template &lt;typename, typename&gt; struct duplicate;
template &lt;std::size_t... is, std::size_t... ts&gt;
struct duplicate&lt;index_list&lt;is...&gt;, index_list&lt;ts...&gt;&gt; : index_list&lt;is..., (sizeof...(is)+is)...,
                                                                         (2*sizeof...(is)+ts)...&gt; {};

template &lt;std::size_t N&gt;
struct make_index_list :
	duplicate&lt; eval&lt;make_index_list&lt;N/2&gt;&gt;,
	           eval&lt;make_index_list&lt;N%2&gt;&gt; &gt; {};

template &lt;&gt; struct make_index_list&lt;1&gt; : index_list&lt;0&gt; {};
template &lt;&gt; struct make_index_list&lt;0&gt; : index_list&lt;&gt; {};

template &lt;std::size_t N&gt;
using make_index_list_t = eval&lt;make_index_list&lt;N&gt;&gt;;

template &lt;typename IL, std::size_t start, std::size_t len, typename=make_index_list_t&lt;len&gt;&gt;
struct sub_list;
template &lt;typename IL, std::size_t start, std::size_t len, std::size_t... indices&gt;
struct sub_list&lt;IL, start, len, index_list&lt;indices...&gt;&gt; : index_list&lt;IL::arr[start+indices]...&gt; {};

/// ////////////////////////////////////////////////////////////////////////////////////////

template &lt;typename T, std::size_t&gt;
struct type_node {using type=T;};
template &lt;std::size_t I, typename U&gt;
identity&lt;U&gt; type_deducer(type_node&lt;U,I&gt;);

template &lt;typename P, typename=make_index_list_t&lt;length&lt;P&gt;&gt;&gt;
struct type_map;
template &lt;typename... T, std::size_t... indices&gt;
struct type_map&lt;pack&lt;T...&gt;, index_list&lt;indices...&gt;&gt; : type_node&lt;T, indices&gt;... {};

template &lt;typename M, std::size_t I&gt;
using get_t = typename decltype(type_deducer&lt;I&gt;(M()))::type;
template &lt;typename P, std::size_t I&gt;
using pack_get_t = typename decltype(type_deducer&lt;I&gt;(type_map&lt;P&gt;()))::type;

template &lt;typename P, std::size_t start, std::size_t len, typename=make_index_list_t&lt;len&gt;&gt;
struct sub_pack;
template &lt;typename P, std::size_t start, std::size_t len, std::size_t... indices&gt;
struct sub_pack&lt;P, start, len, index_list&lt;indices...&gt;&gt; : pack&lt;pack_get_t&lt;P, start+indices&gt;...&gt; {};

/// /////////////////////////////////

template &lt;typename, typename&gt; struct cat;
template &lt;typename... ls, typename... rs&gt;
struct cat&lt;pack&lt;ls...&gt;, pack&lt;rs...&gt;&gt; {using type=pack&lt;ls...,rs...&gt;;};
template &lt;std::size_t... ls, std::size_t... rs&gt;
struct cat&lt;index_list&lt;ls...&gt;, index_list&lt;rs...&gt;&gt; {using type=index_list&lt;ls...,rs...&gt;;};
template &lt;typename A, typename B&gt; using cat_t = eval&lt;cat&lt;A,B&gt;&gt;;

/// ////////////////////////////////////////////////////////////////////////////////////////

template &lt;template&lt;typename, std::size_t&gt; typename F, typename State&gt;
struct reccat {
	template &lt;std::size_t I, std::size_t L&gt;
	struct apply : cat&lt;typename apply&lt;I, L/2&gt;::type,
	                   typename apply&lt;I+L/2, L/2 + L%2&gt;::type&gt; {};
	template &lt;std::size_t I&gt;
	struct apply&lt;I, 1&gt; {using type=typename F&lt;State, I&gt;::type;};
};
template &lt;template&lt;typename, std::size_t&gt; typename F, typename State, std::size_t L&gt;
using reccat_t = typename reccat&lt;F, State&gt;::template apply&lt;0, L&gt;::type;

/// ///////////////////////////////////

template &lt;typename P, std::size_t I&gt;
struct getIndicesImpl {
	template &lt;typename&gt; struct aux : index_list&lt;&gt; {};
	template &lt;typename... _&gt;
	struct aux&lt;pack&lt;_...&gt;&gt; : index_list&lt;I&gt; {};

	using type = typename aux&lt;pack_get_t&lt;P, I&gt;&gt;::type;
};
template &lt;typename P&gt;
struct getIndices : reccat_t&lt;getIndicesImpl, P, length&lt;P&gt;&gt; {};
template &lt;&gt;
struct getIndices&lt;pack&lt;&gt;&gt; : index_list&lt;&gt; {};

template &lt;typename P, typename=typename getIndices&lt;P&gt;::type&gt;
struct flatten;

template &lt;typename P, std::size_t... pack_indices&gt;
struct flatten&lt;P, index_list&lt;pack_indices...&gt;&gt;
{
	using flattened_packs = pack&lt;typename flatten&lt;pack_get_t&lt;P, pack_indices&gt;&gt;::type...&gt;;

	template &lt;typename, std::size_t I&gt;
	struct merge {
		static constexpr auto start_index = I==0? 0 : index_list&lt;pack_indices...&gt;::arr[I-1]+1;
		template &lt;typename=make_index_list_t&lt;index_list&lt;pack_indices...&gt;::arr[I] - start_index&gt;&gt;
		struct aux;
		template &lt;std::size_t... indices&gt;
		struct aux&lt;index_list&lt;indices...&gt;&gt; : cat&lt;pack&lt;pack_get_t&lt;P, start_index+indices&gt;...&gt;,
		                                         pack_get_t&lt;flattened_packs, I&gt;&gt; {};
		using type = eval&lt;aux&lt;&gt;&gt;;
	};

	static constexpr auto tail_start_index = index_list&lt;pack_indices...&gt;::arr[sizeof...(pack_indices)-1]+1;
	using type = cat_t&lt;reccat_t&lt;merge, void, sizeof...(pack_indices)&gt;,
	                   typename sub_pack&lt;P, tail_start_index, length&lt;P&gt;-tail_start_index&gt;::type&gt;;
};

template &lt;typename _&gt; struct flatten&lt;_, index_list&lt;&gt;&gt; {using type = _;};
template &lt;typename... _&gt; struct flatten&lt;pack&lt;pack&lt;_...&gt;&gt;, index_list&lt;0&gt;&gt; {using type = eval&lt;flatten&lt;pack&lt;_...&gt;&gt;&gt;;};

template &lt;typename P&gt;
using flatten_t = eval&lt;flatten&lt;P&gt;&gt;;

/// TESTS:

static_assert(std::is_same&lt;flatten_t&lt;pack&lt;int, float, pack&lt;double, pack&lt;long&gt;, int&gt;, pack&lt;int&gt;, float&gt;&gt;,
                                     pack&lt;int, float,      double,      long,  int,       int,  float&gt;&gt;{});

template &lt;int N&gt;
struct construct {using type=pack&lt;int, double, float, char, bool, long, typename construct&lt;N-1&gt;::type, unsigned long&gt;;};
template &lt;&gt;
struct construct&lt;0&gt; {using type=pack&lt;&gt;;};

using F = flatten_t&lt;construct&lt;64&gt;::type&gt;;
</code></pre>
]]></description><link>https://www.c-plusplus.net/forum/post/2477248</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2477248</guid><dc:creator><![CDATA[Columbo]]></dc:creator><pubDate>Fri, 27 Nov 2015 10:35:14 GMT</pubDate></item><item><title><![CDATA[Reply to flatten_t&amp;lt;&amp;gt; in O(1)? on Fri, 27 Nov 2015 01:04:25 GMT]]></title><description><![CDATA[<p>Oh mein Gott <img
      src="https://www.c-plusplus.net/forum/plugins/nodebb-plugin-emoji/emoji/emoji-one/1f62e.png?v=ab1pehoraso"
      class="not-responsive emoji emoji-emoji-one emoji--face_with_open_mouth"
      title=":open_mouth:"
      alt="😮"
    /></p>
<p>Das versuch ich gar nicht mehr nachzuvollziehen <img
      src="https://www.c-plusplus.net/forum/plugins/nodebb-plugin-emoji/emoji/emoji-one/1f603.png?v=ab1pehoraso"
      class="not-responsive emoji emoji-emoji-one emoji--grinning_face_with_big_eyes"
      title=":D"
      alt="😃"
    /><br />
Das schafft ja sogar rekursiv (flatten_deep), wenn ich das richtige sehe.</p>
<p>Da bleibt mir nur noch Danke zu sagen.</p>
<p>EDIT: Man könnte vielleicht noch optimieren, wenn man die Reihenfolge außer Acht lässt, was aber zumindest in meinem Anwendungsfall leider nicht geht.<br />
(Dafür hatte ich eine Idee mit pack expansion, habe aber den Gedanken noch nicht ganz zu Ende gebracht.).</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2477250</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2477250</guid><dc:creator><![CDATA[5cript]]></dc:creator><pubDate>Fri, 27 Nov 2015 01:04:25 GMT</pubDate></item><item><title><![CDATA[Reply to flatten_t&amp;lt;&amp;gt; in O(1)? on Fri, 27 Nov 2015 01:42:02 GMT]]></title><description><![CDATA[<p>5cript schrieb:</p>
<blockquote>
<p>Das schafft ja sogar rekursiv (flatten_deep), wenn ich das richtige sehe.</p>
</blockquote>
<p>Na darum ging's doch?</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2477253</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2477253</guid><dc:creator><![CDATA[Columbo]]></dc:creator><pubDate>Fri, 27 Nov 2015 01:42:02 GMT</pubDate></item><item><title><![CDATA[Reply to flatten_t&amp;lt;&amp;gt; in O(1)? on Fri, 27 Nov 2015 07:44:39 GMT]]></title><description><![CDATA[<p>Eine Ebene hätte auch (erstmal) gereicht <img
      src="https://www.c-plusplus.net/forum/plugins/nodebb-plugin-emoji/emoji/emoji-one/1f603.png?v=ab1pehoraso"
      class="not-responsive emoji emoji-emoji-one emoji--grinning_face_with_big_eyes"
      title=":D"
      alt="😃"
    /></p>
]]></description><link>https://www.c-plusplus.net/forum/post/2477272</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2477272</guid><dc:creator><![CDATA[5cript]]></dc:creator><pubDate>Fri, 27 Nov 2015 07:44:39 GMT</pubDate></item></channel></rss>