how to flatten nested templates parameters?





.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty{ height:90px;width:728px;box-sizing:border-box;
}







1















Say I have



template<class ... T> pack { };


I want to convert



pack<int, pack<int, pack<int, pack<int>>>>


into



pack<int, int, int, int>


How can I do so?










share|improve this question




















  • 2





    Do you also want to convert stuff like pack<int, pack<int, int>, int>?

    – Holt
    Jan 3 at 16:02


















1















Say I have



template<class ... T> pack { };


I want to convert



pack<int, pack<int, pack<int, pack<int>>>>


into



pack<int, int, int, int>


How can I do so?










share|improve this question




















  • 2





    Do you also want to convert stuff like pack<int, pack<int, int>, int>?

    – Holt
    Jan 3 at 16:02














1












1








1








Say I have



template<class ... T> pack { };


I want to convert



pack<int, pack<int, pack<int, pack<int>>>>


into



pack<int, int, int, int>


How can I do so?










share|improve this question
















Say I have



template<class ... T> pack { };


I want to convert



pack<int, pack<int, pack<int, pack<int>>>>


into



pack<int, int, int, int>


How can I do so?







c++ templates variadic-templates






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Jan 3 at 16:04









NathanOliver

98.8k16138218




98.8k16138218










asked Jan 3 at 16:01









Apliex-DdrApliex-Ddr

1468




1468








  • 2





    Do you also want to convert stuff like pack<int, pack<int, int>, int>?

    – Holt
    Jan 3 at 16:02














  • 2





    Do you also want to convert stuff like pack<int, pack<int, int>, int>?

    – Holt
    Jan 3 at 16:02








2




2





Do you also want to convert stuff like pack<int, pack<int, int>, int>?

– Holt
Jan 3 at 16:02





Do you also want to convert stuff like pack<int, pack<int, int>, int>?

– Holt
Jan 3 at 16:02












7 Answers
7






active

oldest

votes


















2














I propose the following struct and using



template <typename T0, typename...>
struct flatt_helper
{ using type = T0; };

template <typename ... Ts1, typename T0, typename ... Ts2>
struct flatt_helper<pack<Ts1...>, T0, Ts2...>
: flatt_helper<pack<Ts1..., T0>, Ts2...>
{ };

template <typename ... Ts1, template <typename ...> class C,
typename ... Ts2, typename ... Ts3>
struct flatt_helper<pack<Ts1...>, C<Ts2...>, Ts3...>
: flatt_helper<pack<Ts1...>, Ts2..., Ts3...>
{ };

template <typename T>
using flatt = typename flatt_helper<pack<>, T>::type;


This way you can flatten pack and other template-template, as std::tuple, and also more complex examples (the pack<int, pack<int, int>, int> suggested by Holt, by example).



If you want flat only pack, avoiding that all template-template are flattened..., I mean... if you want that



pack<int, pack<int, std::tuple<int, long>>>


is flattened as



pack<int, int, std::tuple<int, long>>


instead of



pack<int, int, int, long>


you have to remove the template-template parameter in the last flatt_helper specialization and simplify it as follows



template <typename ... Ts1, typename ... Ts2, typename ... Ts3>
struct flatt_helper<pack<Ts1...>, pack<Ts2...>, Ts3...>
: flatt_helper<pack<Ts1...>, Ts2..., Ts3...>
{ };


The following is a full compiling example (with full flatting)



#include <tuple>
#include <type_traits>

template <typename...>
struct pack
{ };

template <typename T0, typename...>
struct flatt_helper
{ using type = T0; };

template <typename ... Ts1, typename T0, typename ... Ts2>
struct flatt_helper<pack<Ts1...>, T0, Ts2...>
: flatt_helper<pack<Ts1..., T0>, Ts2...>
{ };

template <typename ... Ts1, template <typename ...> class C,
typename ... Ts2, typename ... Ts3>
struct flatt_helper<pack<Ts1...>, C<Ts2...>, Ts3...>
: flatt_helper<pack<Ts1...>, Ts2..., Ts3...>
{ };

template <typename T>
using flatt = typename flatt_helper<pack<>, T>::type;

int main()
{
using T0 = pack<int, pack<int, pack<int, pack<int>>>>;
using T1 = pack<int, int, int, int>;
using T2 = flatt<T0>;
using T3 = pack<int, pack<int, long>, std::tuple<pack<int, char>, long>>;
using T4 = pack<int, int, long, int, char, long>;
using T5 = flatt<T3>;

static_assert( std::is_same<T1, T2>::value, "!" );
static_assert( std::is_same<T4, T5>::value, "!" );
}





share|improve this answer





















  • 2





    Nice answer with the building up from pack<> but you should point out that, with the template template parameter, this will flatten everything, like flatt<pack<int, std::vector<int>>> is actually pack<int, int, int>, which may not be the expected behavior here.

    – Holt
    Jan 3 at 16:29








  • 1





    @holt I would even call it "wrong".

    – Yakk - Adam Nevraumont
    Jan 3 at 16:40











  • @Holt - yes, wasn't clear; answer modified; hope is clearer now

    – max66
    Jan 3 at 16:48



















2














A possible quick implementation based on std::tuple_cat:



template <class T>
struct tuple_flatten {
using type = std::tuple<T>;
};

template <class... Args>
struct tuple_flatten<pack<Args...>> {
using type = decltype(std::tuple_cat(
typename tuple_flatten<Args>::type{}...));
};

template <class T>
struct tuple_to_pack;

template <class... Args>
struct tuple_to_pack<std::tuple<Args...>> {
using type = pack<Args...>;
};

template <class T>
struct flatten {
using type = typename tuple_to_pack<
typename tuple_flatten<T>::type>::type;
};

template <class T>
using flatten_t = typename flatten<T>::type;




Godbolt demo






share|improve this answer

































    1














    i'd recursively unpack and pack things back:



    template<class Head, class... Packed>
    struct repack
    {
    using type = Head;
    };

    template<class Head, class... Packed>
    struct repack<pack<Head, pack<Packed...>>>
    {
    using type = pack<Head, repack<Packed...>>;
    };


    The type repack<pack<int, pack<int, pack<int, pack<int>>>>>::type get transformed into:




    • pack<int, repack<pack<int, pack<int, pack<int>>>>>

    • pack<int, int, repack<pack<int, pack<int>>>>

    • pack<int, int, int, repack<pack<int>>>

    • pack<int, int, int, int>


    Live demo






    share|improve this answer



















    • 2





      This code does not generate the type you think it does. Nor does it handle `pack<int,int,int> right.

      – Yakk - Adam Nevraumont
      Jan 3 at 16:42



















    1














    Late to the party?



    template <class... Ts> struct flatten;
    template <class... Ts> struct flatten<pack<Ts...>, pack<>>
    {
    using type = pack<Ts...>;
    };
    template <class... Ts> struct flatten<pack<Ts...>>
    : flatten<pack<>, pack<Ts...>>
    { };
    template <class... Ts, class T, class... Rs>
    struct flatten<pack<Ts...>, pack<T, Rs...>> : flatten<pack<Ts...>, T, pack<Rs...>>
    { };
    template <class... Ts, class T, class... Es>
    struct flatten<pack<Ts...>, T, pack<Es...>> : flatten<pack<Ts..., T>, pack<Es...>>
    { };
    template <class... Ts, class... Rs, class... Es>
    struct flatten<pack<Ts...>, pack<Rs...>, pack<Es...>> : flatten<pack<Ts...>, pack<Rs..., Es...>>
    { };

    template <class T> using flatten_t = typename flatten<T>::type;


    using T1 = pack<int, pack<int, int>, pack<int, int>, int>;
    using T2 = pack<int, pack<int, pack<int, pack<int, int>>>, int>;
    using R1 = pack<int,int,int,int,int,int>;

    static_assert(std::is_same_v<R1, flatten_t<T1>>);
    static_assert(std::is_same_v<R1, flatten_t<T2>>);





    share|improve this answer































      0














      pack_cat takes a sequence of packs or non-packs, and concatinates anything that is a pack together, plus items that are not packs.



      template<class T0, class...Ts>
      struct catter;
      template<class...Ts>
      using pack_cat = typename catter<Ts...>::type;
      template<class T0>
      struct catter<T0>{ using type=T0; };
      template<class...Ts, class...Us, class...Vs>
      struct catter<pack<Ts...>, pack<Us...>, Vs...>{ using type=pack_cat<pack<Ts...,Us...>,Vs...>; };
      template<class...Ts, class U, class...Vs>
      struct catter<pack<Ts...>, U, Vs...>{ using type=pack_cat<pack<Ts...,U>,Vs...>; };


      unpacker takes a pack, and recursively unpacks all sub-packs and concatinates them.



      template<class X>
      struct unpacker{using type=X;};
      template<class X>
      using unpack=typename unpacker<X>::type;
      template<class...Ts>
      struct unpacker<pack<Ts...>>{using type=pack_cat<pack<>,unpack<Ts>...>;};


      To test it:



      pack<int,int,int,int>{}=unpack<pack<int,pack<int,pack<int,pack<int>>>>>{};
      pack<int,int,int>{} = unpack<pack<int,int,int>>{};
      pack<int,int,int>{} = unpack<pack<pack<int,int>,int>>{};


      which compile IFF the two types are the same.






      share|improve this answer































        0














        template< typename >
        struct is_tuple: false_type{};

        template<typename ... input_t>
        struct is_tuple< std::tuple<input_t ... > > :
        true_type{};

        template<typename ... input_t> using flat_tuple= decltype(std::tuple_cat( std::declval< std::conditional_t< is_tuple< input_t >::value, input_t, std::tuple< input_t > > >()... ) );





        share|improve this answer































          0














          And now... for something completely different... (well... not completely... almost the Holt's solutions but using functions instead of structs)



          You can combine std::tuple_cat() with decltype() in a couple of declared function to flat a pack in a std::tuple



          template <typename T>
          constexpr std::tuple<T> foo (T);

          template <typename ... Ts>
          constexpr auto foo (pack<Ts...>)
          -> decltype( std::tuple_cat(foo(std::declval<Ts>())...) );


          and another declared functions that convert the flattened std::tuple again in a pack



          template <typename ... Ts>
          constexpr pack<Ts...> bar (std::tuple<Ts...>);


          Now you can combine in a flattener as follows



          template <typename T>
          using fl = decltype(bar(foo(std::declval<T>())));


          The following is a full compiling example



          #include <tuple>
          #include <type_traits>

          template <typename...>
          struct pack
          { };

          template <typename T>
          constexpr std::tuple<T> foo (T);

          template <typename ... Ts>
          constexpr auto foo (pack<Ts...>)
          -> decltype( std::tuple_cat(foo(std::declval<Ts>())...) );

          template <typename ... Ts>
          constexpr pack<Ts...> bar (std::tuple<Ts...>);

          template <typename T>
          using fl = decltype(bar(foo(std::declval<T>())));

          int main()
          {
          using U0 = pack<int, pack<int, pack<int, pack<int>>>>;
          using U1 = pack<int, int, int, int>;
          using U2 = fl<U0>;
          using U3 = pack<int, pack<int, long>, pack<pack<int, char>, long>>;
          using U4 = pack<int, int, long, int, char, long>;
          using U5 = fl<U3>;

          static_assert( std::is_same<U1, U2>::value, "!" );
          static_assert( std::is_same<U4, U5>::value, "!" );
          }





          share|improve this answer
























            Your Answer






            StackExchange.ifUsing("editor", function () {
            StackExchange.using("externalEditor", function () {
            StackExchange.using("snippets", function () {
            StackExchange.snippets.init();
            });
            });
            }, "code-snippets");

            StackExchange.ready(function() {
            var channelOptions = {
            tags: "".split(" "),
            id: "1"
            };
            initTagRenderer("".split(" "), "".split(" "), channelOptions);

            StackExchange.using("externalEditor", function() {
            // Have to fire editor after snippets, if snippets enabled
            if (StackExchange.settings.snippets.snippetsEnabled) {
            StackExchange.using("snippets", function() {
            createEditor();
            });
            }
            else {
            createEditor();
            }
            });

            function createEditor() {
            StackExchange.prepareEditor({
            heartbeatType: 'answer',
            autoActivateHeartbeat: false,
            convertImagesToLinks: true,
            noModals: true,
            showLowRepImageUploadWarning: true,
            reputationToPostImages: 10,
            bindNavPrevention: true,
            postfix: "",
            imageUploader: {
            brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
            contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
            allowUrls: true
            },
            onDemand: true,
            discardSelector: ".discard-answer"
            ,immediatelyShowMarkdownHelp:true
            });


            }
            });














            draft saved

            draft discarded


















            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54025813%2fhow-to-flatten-nested-templates-parameters%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown

























            7 Answers
            7






            active

            oldest

            votes








            7 Answers
            7






            active

            oldest

            votes









            active

            oldest

            votes






            active

            oldest

            votes









            2














            I propose the following struct and using



            template <typename T0, typename...>
            struct flatt_helper
            { using type = T0; };

            template <typename ... Ts1, typename T0, typename ... Ts2>
            struct flatt_helper<pack<Ts1...>, T0, Ts2...>
            : flatt_helper<pack<Ts1..., T0>, Ts2...>
            { };

            template <typename ... Ts1, template <typename ...> class C,
            typename ... Ts2, typename ... Ts3>
            struct flatt_helper<pack<Ts1...>, C<Ts2...>, Ts3...>
            : flatt_helper<pack<Ts1...>, Ts2..., Ts3...>
            { };

            template <typename T>
            using flatt = typename flatt_helper<pack<>, T>::type;


            This way you can flatten pack and other template-template, as std::tuple, and also more complex examples (the pack<int, pack<int, int>, int> suggested by Holt, by example).



            If you want flat only pack, avoiding that all template-template are flattened..., I mean... if you want that



            pack<int, pack<int, std::tuple<int, long>>>


            is flattened as



            pack<int, int, std::tuple<int, long>>


            instead of



            pack<int, int, int, long>


            you have to remove the template-template parameter in the last flatt_helper specialization and simplify it as follows



            template <typename ... Ts1, typename ... Ts2, typename ... Ts3>
            struct flatt_helper<pack<Ts1...>, pack<Ts2...>, Ts3...>
            : flatt_helper<pack<Ts1...>, Ts2..., Ts3...>
            { };


            The following is a full compiling example (with full flatting)



            #include <tuple>
            #include <type_traits>

            template <typename...>
            struct pack
            { };

            template <typename T0, typename...>
            struct flatt_helper
            { using type = T0; };

            template <typename ... Ts1, typename T0, typename ... Ts2>
            struct flatt_helper<pack<Ts1...>, T0, Ts2...>
            : flatt_helper<pack<Ts1..., T0>, Ts2...>
            { };

            template <typename ... Ts1, template <typename ...> class C,
            typename ... Ts2, typename ... Ts3>
            struct flatt_helper<pack<Ts1...>, C<Ts2...>, Ts3...>
            : flatt_helper<pack<Ts1...>, Ts2..., Ts3...>
            { };

            template <typename T>
            using flatt = typename flatt_helper<pack<>, T>::type;

            int main()
            {
            using T0 = pack<int, pack<int, pack<int, pack<int>>>>;
            using T1 = pack<int, int, int, int>;
            using T2 = flatt<T0>;
            using T3 = pack<int, pack<int, long>, std::tuple<pack<int, char>, long>>;
            using T4 = pack<int, int, long, int, char, long>;
            using T5 = flatt<T3>;

            static_assert( std::is_same<T1, T2>::value, "!" );
            static_assert( std::is_same<T4, T5>::value, "!" );
            }





            share|improve this answer





















            • 2





              Nice answer with the building up from pack<> but you should point out that, with the template template parameter, this will flatten everything, like flatt<pack<int, std::vector<int>>> is actually pack<int, int, int>, which may not be the expected behavior here.

              – Holt
              Jan 3 at 16:29








            • 1





              @holt I would even call it "wrong".

              – Yakk - Adam Nevraumont
              Jan 3 at 16:40











            • @Holt - yes, wasn't clear; answer modified; hope is clearer now

              – max66
              Jan 3 at 16:48
















            2














            I propose the following struct and using



            template <typename T0, typename...>
            struct flatt_helper
            { using type = T0; };

            template <typename ... Ts1, typename T0, typename ... Ts2>
            struct flatt_helper<pack<Ts1...>, T0, Ts2...>
            : flatt_helper<pack<Ts1..., T0>, Ts2...>
            { };

            template <typename ... Ts1, template <typename ...> class C,
            typename ... Ts2, typename ... Ts3>
            struct flatt_helper<pack<Ts1...>, C<Ts2...>, Ts3...>
            : flatt_helper<pack<Ts1...>, Ts2..., Ts3...>
            { };

            template <typename T>
            using flatt = typename flatt_helper<pack<>, T>::type;


            This way you can flatten pack and other template-template, as std::tuple, and also more complex examples (the pack<int, pack<int, int>, int> suggested by Holt, by example).



            If you want flat only pack, avoiding that all template-template are flattened..., I mean... if you want that



            pack<int, pack<int, std::tuple<int, long>>>


            is flattened as



            pack<int, int, std::tuple<int, long>>


            instead of



            pack<int, int, int, long>


            you have to remove the template-template parameter in the last flatt_helper specialization and simplify it as follows



            template <typename ... Ts1, typename ... Ts2, typename ... Ts3>
            struct flatt_helper<pack<Ts1...>, pack<Ts2...>, Ts3...>
            : flatt_helper<pack<Ts1...>, Ts2..., Ts3...>
            { };


            The following is a full compiling example (with full flatting)



            #include <tuple>
            #include <type_traits>

            template <typename...>
            struct pack
            { };

            template <typename T0, typename...>
            struct flatt_helper
            { using type = T0; };

            template <typename ... Ts1, typename T0, typename ... Ts2>
            struct flatt_helper<pack<Ts1...>, T0, Ts2...>
            : flatt_helper<pack<Ts1..., T0>, Ts2...>
            { };

            template <typename ... Ts1, template <typename ...> class C,
            typename ... Ts2, typename ... Ts3>
            struct flatt_helper<pack<Ts1...>, C<Ts2...>, Ts3...>
            : flatt_helper<pack<Ts1...>, Ts2..., Ts3...>
            { };

            template <typename T>
            using flatt = typename flatt_helper<pack<>, T>::type;

            int main()
            {
            using T0 = pack<int, pack<int, pack<int, pack<int>>>>;
            using T1 = pack<int, int, int, int>;
            using T2 = flatt<T0>;
            using T3 = pack<int, pack<int, long>, std::tuple<pack<int, char>, long>>;
            using T4 = pack<int, int, long, int, char, long>;
            using T5 = flatt<T3>;

            static_assert( std::is_same<T1, T2>::value, "!" );
            static_assert( std::is_same<T4, T5>::value, "!" );
            }





            share|improve this answer





















            • 2





              Nice answer with the building up from pack<> but you should point out that, with the template template parameter, this will flatten everything, like flatt<pack<int, std::vector<int>>> is actually pack<int, int, int>, which may not be the expected behavior here.

              – Holt
              Jan 3 at 16:29








            • 1





              @holt I would even call it "wrong".

              – Yakk - Adam Nevraumont
              Jan 3 at 16:40











            • @Holt - yes, wasn't clear; answer modified; hope is clearer now

              – max66
              Jan 3 at 16:48














            2












            2








            2







            I propose the following struct and using



            template <typename T0, typename...>
            struct flatt_helper
            { using type = T0; };

            template <typename ... Ts1, typename T0, typename ... Ts2>
            struct flatt_helper<pack<Ts1...>, T0, Ts2...>
            : flatt_helper<pack<Ts1..., T0>, Ts2...>
            { };

            template <typename ... Ts1, template <typename ...> class C,
            typename ... Ts2, typename ... Ts3>
            struct flatt_helper<pack<Ts1...>, C<Ts2...>, Ts3...>
            : flatt_helper<pack<Ts1...>, Ts2..., Ts3...>
            { };

            template <typename T>
            using flatt = typename flatt_helper<pack<>, T>::type;


            This way you can flatten pack and other template-template, as std::tuple, and also more complex examples (the pack<int, pack<int, int>, int> suggested by Holt, by example).



            If you want flat only pack, avoiding that all template-template are flattened..., I mean... if you want that



            pack<int, pack<int, std::tuple<int, long>>>


            is flattened as



            pack<int, int, std::tuple<int, long>>


            instead of



            pack<int, int, int, long>


            you have to remove the template-template parameter in the last flatt_helper specialization and simplify it as follows



            template <typename ... Ts1, typename ... Ts2, typename ... Ts3>
            struct flatt_helper<pack<Ts1...>, pack<Ts2...>, Ts3...>
            : flatt_helper<pack<Ts1...>, Ts2..., Ts3...>
            { };


            The following is a full compiling example (with full flatting)



            #include <tuple>
            #include <type_traits>

            template <typename...>
            struct pack
            { };

            template <typename T0, typename...>
            struct flatt_helper
            { using type = T0; };

            template <typename ... Ts1, typename T0, typename ... Ts2>
            struct flatt_helper<pack<Ts1...>, T0, Ts2...>
            : flatt_helper<pack<Ts1..., T0>, Ts2...>
            { };

            template <typename ... Ts1, template <typename ...> class C,
            typename ... Ts2, typename ... Ts3>
            struct flatt_helper<pack<Ts1...>, C<Ts2...>, Ts3...>
            : flatt_helper<pack<Ts1...>, Ts2..., Ts3...>
            { };

            template <typename T>
            using flatt = typename flatt_helper<pack<>, T>::type;

            int main()
            {
            using T0 = pack<int, pack<int, pack<int, pack<int>>>>;
            using T1 = pack<int, int, int, int>;
            using T2 = flatt<T0>;
            using T3 = pack<int, pack<int, long>, std::tuple<pack<int, char>, long>>;
            using T4 = pack<int, int, long, int, char, long>;
            using T5 = flatt<T3>;

            static_assert( std::is_same<T1, T2>::value, "!" );
            static_assert( std::is_same<T4, T5>::value, "!" );
            }





            share|improve this answer















            I propose the following struct and using



            template <typename T0, typename...>
            struct flatt_helper
            { using type = T0; };

            template <typename ... Ts1, typename T0, typename ... Ts2>
            struct flatt_helper<pack<Ts1...>, T0, Ts2...>
            : flatt_helper<pack<Ts1..., T0>, Ts2...>
            { };

            template <typename ... Ts1, template <typename ...> class C,
            typename ... Ts2, typename ... Ts3>
            struct flatt_helper<pack<Ts1...>, C<Ts2...>, Ts3...>
            : flatt_helper<pack<Ts1...>, Ts2..., Ts3...>
            { };

            template <typename T>
            using flatt = typename flatt_helper<pack<>, T>::type;


            This way you can flatten pack and other template-template, as std::tuple, and also more complex examples (the pack<int, pack<int, int>, int> suggested by Holt, by example).



            If you want flat only pack, avoiding that all template-template are flattened..., I mean... if you want that



            pack<int, pack<int, std::tuple<int, long>>>


            is flattened as



            pack<int, int, std::tuple<int, long>>


            instead of



            pack<int, int, int, long>


            you have to remove the template-template parameter in the last flatt_helper specialization and simplify it as follows



            template <typename ... Ts1, typename ... Ts2, typename ... Ts3>
            struct flatt_helper<pack<Ts1...>, pack<Ts2...>, Ts3...>
            : flatt_helper<pack<Ts1...>, Ts2..., Ts3...>
            { };


            The following is a full compiling example (with full flatting)



            #include <tuple>
            #include <type_traits>

            template <typename...>
            struct pack
            { };

            template <typename T0, typename...>
            struct flatt_helper
            { using type = T0; };

            template <typename ... Ts1, typename T0, typename ... Ts2>
            struct flatt_helper<pack<Ts1...>, T0, Ts2...>
            : flatt_helper<pack<Ts1..., T0>, Ts2...>
            { };

            template <typename ... Ts1, template <typename ...> class C,
            typename ... Ts2, typename ... Ts3>
            struct flatt_helper<pack<Ts1...>, C<Ts2...>, Ts3...>
            : flatt_helper<pack<Ts1...>, Ts2..., Ts3...>
            { };

            template <typename T>
            using flatt = typename flatt_helper<pack<>, T>::type;

            int main()
            {
            using T0 = pack<int, pack<int, pack<int, pack<int>>>>;
            using T1 = pack<int, int, int, int>;
            using T2 = flatt<T0>;
            using T3 = pack<int, pack<int, long>, std::tuple<pack<int, char>, long>>;
            using T4 = pack<int, int, long, int, char, long>;
            using T5 = flatt<T3>;

            static_assert( std::is_same<T1, T2>::value, "!" );
            static_assert( std::is_same<T4, T5>::value, "!" );
            }






            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited Jan 3 at 16:47

























            answered Jan 3 at 16:20









            max66max66

            39.4k74575




            39.4k74575








            • 2





              Nice answer with the building up from pack<> but you should point out that, with the template template parameter, this will flatten everything, like flatt<pack<int, std::vector<int>>> is actually pack<int, int, int>, which may not be the expected behavior here.

              – Holt
              Jan 3 at 16:29








            • 1





              @holt I would even call it "wrong".

              – Yakk - Adam Nevraumont
              Jan 3 at 16:40











            • @Holt - yes, wasn't clear; answer modified; hope is clearer now

              – max66
              Jan 3 at 16:48














            • 2





              Nice answer with the building up from pack<> but you should point out that, with the template template parameter, this will flatten everything, like flatt<pack<int, std::vector<int>>> is actually pack<int, int, int>, which may not be the expected behavior here.

              – Holt
              Jan 3 at 16:29








            • 1





              @holt I would even call it "wrong".

              – Yakk - Adam Nevraumont
              Jan 3 at 16:40











            • @Holt - yes, wasn't clear; answer modified; hope is clearer now

              – max66
              Jan 3 at 16:48








            2




            2





            Nice answer with the building up from pack<> but you should point out that, with the template template parameter, this will flatten everything, like flatt<pack<int, std::vector<int>>> is actually pack<int, int, int>, which may not be the expected behavior here.

            – Holt
            Jan 3 at 16:29







            Nice answer with the building up from pack<> but you should point out that, with the template template parameter, this will flatten everything, like flatt<pack<int, std::vector<int>>> is actually pack<int, int, int>, which may not be the expected behavior here.

            – Holt
            Jan 3 at 16:29






            1




            1





            @holt I would even call it "wrong".

            – Yakk - Adam Nevraumont
            Jan 3 at 16:40





            @holt I would even call it "wrong".

            – Yakk - Adam Nevraumont
            Jan 3 at 16:40













            @Holt - yes, wasn't clear; answer modified; hope is clearer now

            – max66
            Jan 3 at 16:48





            @Holt - yes, wasn't clear; answer modified; hope is clearer now

            – max66
            Jan 3 at 16:48













            2














            A possible quick implementation based on std::tuple_cat:



            template <class T>
            struct tuple_flatten {
            using type = std::tuple<T>;
            };

            template <class... Args>
            struct tuple_flatten<pack<Args...>> {
            using type = decltype(std::tuple_cat(
            typename tuple_flatten<Args>::type{}...));
            };

            template <class T>
            struct tuple_to_pack;

            template <class... Args>
            struct tuple_to_pack<std::tuple<Args...>> {
            using type = pack<Args...>;
            };

            template <class T>
            struct flatten {
            using type = typename tuple_to_pack<
            typename tuple_flatten<T>::type>::type;
            };

            template <class T>
            using flatten_t = typename flatten<T>::type;




            Godbolt demo






            share|improve this answer






























              2














              A possible quick implementation based on std::tuple_cat:



              template <class T>
              struct tuple_flatten {
              using type = std::tuple<T>;
              };

              template <class... Args>
              struct tuple_flatten<pack<Args...>> {
              using type = decltype(std::tuple_cat(
              typename tuple_flatten<Args>::type{}...));
              };

              template <class T>
              struct tuple_to_pack;

              template <class... Args>
              struct tuple_to_pack<std::tuple<Args...>> {
              using type = pack<Args...>;
              };

              template <class T>
              struct flatten {
              using type = typename tuple_to_pack<
              typename tuple_flatten<T>::type>::type;
              };

              template <class T>
              using flatten_t = typename flatten<T>::type;




              Godbolt demo






              share|improve this answer




























                2












                2








                2







                A possible quick implementation based on std::tuple_cat:



                template <class T>
                struct tuple_flatten {
                using type = std::tuple<T>;
                };

                template <class... Args>
                struct tuple_flatten<pack<Args...>> {
                using type = decltype(std::tuple_cat(
                typename tuple_flatten<Args>::type{}...));
                };

                template <class T>
                struct tuple_to_pack;

                template <class... Args>
                struct tuple_to_pack<std::tuple<Args...>> {
                using type = pack<Args...>;
                };

                template <class T>
                struct flatten {
                using type = typename tuple_to_pack<
                typename tuple_flatten<T>::type>::type;
                };

                template <class T>
                using flatten_t = typename flatten<T>::type;




                Godbolt demo






                share|improve this answer















                A possible quick implementation based on std::tuple_cat:



                template <class T>
                struct tuple_flatten {
                using type = std::tuple<T>;
                };

                template <class... Args>
                struct tuple_flatten<pack<Args...>> {
                using type = decltype(std::tuple_cat(
                typename tuple_flatten<Args>::type{}...));
                };

                template <class T>
                struct tuple_to_pack;

                template <class... Args>
                struct tuple_to_pack<std::tuple<Args...>> {
                using type = pack<Args...>;
                };

                template <class T>
                struct flatten {
                using type = typename tuple_to_pack<
                typename tuple_flatten<T>::type>::type;
                };

                template <class T>
                using flatten_t = typename flatten<T>::type;




                Godbolt demo







                share|improve this answer














                share|improve this answer



                share|improve this answer








                edited Jan 3 at 16:16

























                answered Jan 3 at 16:09









                HoltHolt

                25.9k65195




                25.9k65195























                    1














                    i'd recursively unpack and pack things back:



                    template<class Head, class... Packed>
                    struct repack
                    {
                    using type = Head;
                    };

                    template<class Head, class... Packed>
                    struct repack<pack<Head, pack<Packed...>>>
                    {
                    using type = pack<Head, repack<Packed...>>;
                    };


                    The type repack<pack<int, pack<int, pack<int, pack<int>>>>>::type get transformed into:




                    • pack<int, repack<pack<int, pack<int, pack<int>>>>>

                    • pack<int, int, repack<pack<int, pack<int>>>>

                    • pack<int, int, int, repack<pack<int>>>

                    • pack<int, int, int, int>


                    Live demo






                    share|improve this answer



















                    • 2





                      This code does not generate the type you think it does. Nor does it handle `pack<int,int,int> right.

                      – Yakk - Adam Nevraumont
                      Jan 3 at 16:42
















                    1














                    i'd recursively unpack and pack things back:



                    template<class Head, class... Packed>
                    struct repack
                    {
                    using type = Head;
                    };

                    template<class Head, class... Packed>
                    struct repack<pack<Head, pack<Packed...>>>
                    {
                    using type = pack<Head, repack<Packed...>>;
                    };


                    The type repack<pack<int, pack<int, pack<int, pack<int>>>>>::type get transformed into:




                    • pack<int, repack<pack<int, pack<int, pack<int>>>>>

                    • pack<int, int, repack<pack<int, pack<int>>>>

                    • pack<int, int, int, repack<pack<int>>>

                    • pack<int, int, int, int>


                    Live demo






                    share|improve this answer



















                    • 2





                      This code does not generate the type you think it does. Nor does it handle `pack<int,int,int> right.

                      – Yakk - Adam Nevraumont
                      Jan 3 at 16:42














                    1












                    1








                    1







                    i'd recursively unpack and pack things back:



                    template<class Head, class... Packed>
                    struct repack
                    {
                    using type = Head;
                    };

                    template<class Head, class... Packed>
                    struct repack<pack<Head, pack<Packed...>>>
                    {
                    using type = pack<Head, repack<Packed...>>;
                    };


                    The type repack<pack<int, pack<int, pack<int, pack<int>>>>>::type get transformed into:




                    • pack<int, repack<pack<int, pack<int, pack<int>>>>>

                    • pack<int, int, repack<pack<int, pack<int>>>>

                    • pack<int, int, int, repack<pack<int>>>

                    • pack<int, int, int, int>


                    Live demo






                    share|improve this answer













                    i'd recursively unpack and pack things back:



                    template<class Head, class... Packed>
                    struct repack
                    {
                    using type = Head;
                    };

                    template<class Head, class... Packed>
                    struct repack<pack<Head, pack<Packed...>>>
                    {
                    using type = pack<Head, repack<Packed...>>;
                    };


                    The type repack<pack<int, pack<int, pack<int, pack<int>>>>>::type get transformed into:




                    • pack<int, repack<pack<int, pack<int, pack<int>>>>>

                    • pack<int, int, repack<pack<int, pack<int>>>>

                    • pack<int, int, int, repack<pack<int>>>

                    • pack<int, int, int, int>


                    Live demo







                    share|improve this answer












                    share|improve this answer



                    share|improve this answer










                    answered Jan 3 at 16:12









                    YSCYSC

                    25.7k657112




                    25.7k657112








                    • 2





                      This code does not generate the type you think it does. Nor does it handle `pack<int,int,int> right.

                      – Yakk - Adam Nevraumont
                      Jan 3 at 16:42














                    • 2





                      This code does not generate the type you think it does. Nor does it handle `pack<int,int,int> right.

                      – Yakk - Adam Nevraumont
                      Jan 3 at 16:42








                    2




                    2





                    This code does not generate the type you think it does. Nor does it handle `pack<int,int,int> right.

                    – Yakk - Adam Nevraumont
                    Jan 3 at 16:42





                    This code does not generate the type you think it does. Nor does it handle `pack<int,int,int> right.

                    – Yakk - Adam Nevraumont
                    Jan 3 at 16:42











                    1














                    Late to the party?



                    template <class... Ts> struct flatten;
                    template <class... Ts> struct flatten<pack<Ts...>, pack<>>
                    {
                    using type = pack<Ts...>;
                    };
                    template <class... Ts> struct flatten<pack<Ts...>>
                    : flatten<pack<>, pack<Ts...>>
                    { };
                    template <class... Ts, class T, class... Rs>
                    struct flatten<pack<Ts...>, pack<T, Rs...>> : flatten<pack<Ts...>, T, pack<Rs...>>
                    { };
                    template <class... Ts, class T, class... Es>
                    struct flatten<pack<Ts...>, T, pack<Es...>> : flatten<pack<Ts..., T>, pack<Es...>>
                    { };
                    template <class... Ts, class... Rs, class... Es>
                    struct flatten<pack<Ts...>, pack<Rs...>, pack<Es...>> : flatten<pack<Ts...>, pack<Rs..., Es...>>
                    { };

                    template <class T> using flatten_t = typename flatten<T>::type;


                    using T1 = pack<int, pack<int, int>, pack<int, int>, int>;
                    using T2 = pack<int, pack<int, pack<int, pack<int, int>>>, int>;
                    using R1 = pack<int,int,int,int,int,int>;

                    static_assert(std::is_same_v<R1, flatten_t<T1>>);
                    static_assert(std::is_same_v<R1, flatten_t<T2>>);





                    share|improve this answer




























                      1














                      Late to the party?



                      template <class... Ts> struct flatten;
                      template <class... Ts> struct flatten<pack<Ts...>, pack<>>
                      {
                      using type = pack<Ts...>;
                      };
                      template <class... Ts> struct flatten<pack<Ts...>>
                      : flatten<pack<>, pack<Ts...>>
                      { };
                      template <class... Ts, class T, class... Rs>
                      struct flatten<pack<Ts...>, pack<T, Rs...>> : flatten<pack<Ts...>, T, pack<Rs...>>
                      { };
                      template <class... Ts, class T, class... Es>
                      struct flatten<pack<Ts...>, T, pack<Es...>> : flatten<pack<Ts..., T>, pack<Es...>>
                      { };
                      template <class... Ts, class... Rs, class... Es>
                      struct flatten<pack<Ts...>, pack<Rs...>, pack<Es...>> : flatten<pack<Ts...>, pack<Rs..., Es...>>
                      { };

                      template <class T> using flatten_t = typename flatten<T>::type;


                      using T1 = pack<int, pack<int, int>, pack<int, int>, int>;
                      using T2 = pack<int, pack<int, pack<int, pack<int, int>>>, int>;
                      using R1 = pack<int,int,int,int,int,int>;

                      static_assert(std::is_same_v<R1, flatten_t<T1>>);
                      static_assert(std::is_same_v<R1, flatten_t<T2>>);





                      share|improve this answer


























                        1












                        1








                        1







                        Late to the party?



                        template <class... Ts> struct flatten;
                        template <class... Ts> struct flatten<pack<Ts...>, pack<>>
                        {
                        using type = pack<Ts...>;
                        };
                        template <class... Ts> struct flatten<pack<Ts...>>
                        : flatten<pack<>, pack<Ts...>>
                        { };
                        template <class... Ts, class T, class... Rs>
                        struct flatten<pack<Ts...>, pack<T, Rs...>> : flatten<pack<Ts...>, T, pack<Rs...>>
                        { };
                        template <class... Ts, class T, class... Es>
                        struct flatten<pack<Ts...>, T, pack<Es...>> : flatten<pack<Ts..., T>, pack<Es...>>
                        { };
                        template <class... Ts, class... Rs, class... Es>
                        struct flatten<pack<Ts...>, pack<Rs...>, pack<Es...>> : flatten<pack<Ts...>, pack<Rs..., Es...>>
                        { };

                        template <class T> using flatten_t = typename flatten<T>::type;


                        using T1 = pack<int, pack<int, int>, pack<int, int>, int>;
                        using T2 = pack<int, pack<int, pack<int, pack<int, int>>>, int>;
                        using R1 = pack<int,int,int,int,int,int>;

                        static_assert(std::is_same_v<R1, flatten_t<T1>>);
                        static_assert(std::is_same_v<R1, flatten_t<T2>>);





                        share|improve this answer













                        Late to the party?



                        template <class... Ts> struct flatten;
                        template <class... Ts> struct flatten<pack<Ts...>, pack<>>
                        {
                        using type = pack<Ts...>;
                        };
                        template <class... Ts> struct flatten<pack<Ts...>>
                        : flatten<pack<>, pack<Ts...>>
                        { };
                        template <class... Ts, class T, class... Rs>
                        struct flatten<pack<Ts...>, pack<T, Rs...>> : flatten<pack<Ts...>, T, pack<Rs...>>
                        { };
                        template <class... Ts, class T, class... Es>
                        struct flatten<pack<Ts...>, T, pack<Es...>> : flatten<pack<Ts..., T>, pack<Es...>>
                        { };
                        template <class... Ts, class... Rs, class... Es>
                        struct flatten<pack<Ts...>, pack<Rs...>, pack<Es...>> : flatten<pack<Ts...>, pack<Rs..., Es...>>
                        { };

                        template <class T> using flatten_t = typename flatten<T>::type;


                        using T1 = pack<int, pack<int, int>, pack<int, int>, int>;
                        using T2 = pack<int, pack<int, pack<int, pack<int, int>>>, int>;
                        using R1 = pack<int,int,int,int,int,int>;

                        static_assert(std::is_same_v<R1, flatten_t<T1>>);
                        static_assert(std::is_same_v<R1, flatten_t<T2>>);






                        share|improve this answer












                        share|improve this answer



                        share|improve this answer










                        answered Jan 3 at 21:12









                        JansJans

                        9,19422735




                        9,19422735























                            0














                            pack_cat takes a sequence of packs or non-packs, and concatinates anything that is a pack together, plus items that are not packs.



                            template<class T0, class...Ts>
                            struct catter;
                            template<class...Ts>
                            using pack_cat = typename catter<Ts...>::type;
                            template<class T0>
                            struct catter<T0>{ using type=T0; };
                            template<class...Ts, class...Us, class...Vs>
                            struct catter<pack<Ts...>, pack<Us...>, Vs...>{ using type=pack_cat<pack<Ts...,Us...>,Vs...>; };
                            template<class...Ts, class U, class...Vs>
                            struct catter<pack<Ts...>, U, Vs...>{ using type=pack_cat<pack<Ts...,U>,Vs...>; };


                            unpacker takes a pack, and recursively unpacks all sub-packs and concatinates them.



                            template<class X>
                            struct unpacker{using type=X;};
                            template<class X>
                            using unpack=typename unpacker<X>::type;
                            template<class...Ts>
                            struct unpacker<pack<Ts...>>{using type=pack_cat<pack<>,unpack<Ts>...>;};


                            To test it:



                            pack<int,int,int,int>{}=unpack<pack<int,pack<int,pack<int,pack<int>>>>>{};
                            pack<int,int,int>{} = unpack<pack<int,int,int>>{};
                            pack<int,int,int>{} = unpack<pack<pack<int,int>,int>>{};


                            which compile IFF the two types are the same.






                            share|improve this answer




























                              0














                              pack_cat takes a sequence of packs or non-packs, and concatinates anything that is a pack together, plus items that are not packs.



                              template<class T0, class...Ts>
                              struct catter;
                              template<class...Ts>
                              using pack_cat = typename catter<Ts...>::type;
                              template<class T0>
                              struct catter<T0>{ using type=T0; };
                              template<class...Ts, class...Us, class...Vs>
                              struct catter<pack<Ts...>, pack<Us...>, Vs...>{ using type=pack_cat<pack<Ts...,Us...>,Vs...>; };
                              template<class...Ts, class U, class...Vs>
                              struct catter<pack<Ts...>, U, Vs...>{ using type=pack_cat<pack<Ts...,U>,Vs...>; };


                              unpacker takes a pack, and recursively unpacks all sub-packs and concatinates them.



                              template<class X>
                              struct unpacker{using type=X;};
                              template<class X>
                              using unpack=typename unpacker<X>::type;
                              template<class...Ts>
                              struct unpacker<pack<Ts...>>{using type=pack_cat<pack<>,unpack<Ts>...>;};


                              To test it:



                              pack<int,int,int,int>{}=unpack<pack<int,pack<int,pack<int,pack<int>>>>>{};
                              pack<int,int,int>{} = unpack<pack<int,int,int>>{};
                              pack<int,int,int>{} = unpack<pack<pack<int,int>,int>>{};


                              which compile IFF the two types are the same.






                              share|improve this answer


























                                0












                                0








                                0







                                pack_cat takes a sequence of packs or non-packs, and concatinates anything that is a pack together, plus items that are not packs.



                                template<class T0, class...Ts>
                                struct catter;
                                template<class...Ts>
                                using pack_cat = typename catter<Ts...>::type;
                                template<class T0>
                                struct catter<T0>{ using type=T0; };
                                template<class...Ts, class...Us, class...Vs>
                                struct catter<pack<Ts...>, pack<Us...>, Vs...>{ using type=pack_cat<pack<Ts...,Us...>,Vs...>; };
                                template<class...Ts, class U, class...Vs>
                                struct catter<pack<Ts...>, U, Vs...>{ using type=pack_cat<pack<Ts...,U>,Vs...>; };


                                unpacker takes a pack, and recursively unpacks all sub-packs and concatinates them.



                                template<class X>
                                struct unpacker{using type=X;};
                                template<class X>
                                using unpack=typename unpacker<X>::type;
                                template<class...Ts>
                                struct unpacker<pack<Ts...>>{using type=pack_cat<pack<>,unpack<Ts>...>;};


                                To test it:



                                pack<int,int,int,int>{}=unpack<pack<int,pack<int,pack<int,pack<int>>>>>{};
                                pack<int,int,int>{} = unpack<pack<int,int,int>>{};
                                pack<int,int,int>{} = unpack<pack<pack<int,int>,int>>{};


                                which compile IFF the two types are the same.






                                share|improve this answer













                                pack_cat takes a sequence of packs or non-packs, and concatinates anything that is a pack together, plus items that are not packs.



                                template<class T0, class...Ts>
                                struct catter;
                                template<class...Ts>
                                using pack_cat = typename catter<Ts...>::type;
                                template<class T0>
                                struct catter<T0>{ using type=T0; };
                                template<class...Ts, class...Us, class...Vs>
                                struct catter<pack<Ts...>, pack<Us...>, Vs...>{ using type=pack_cat<pack<Ts...,Us...>,Vs...>; };
                                template<class...Ts, class U, class...Vs>
                                struct catter<pack<Ts...>, U, Vs...>{ using type=pack_cat<pack<Ts...,U>,Vs...>; };


                                unpacker takes a pack, and recursively unpacks all sub-packs and concatinates them.



                                template<class X>
                                struct unpacker{using type=X;};
                                template<class X>
                                using unpack=typename unpacker<X>::type;
                                template<class...Ts>
                                struct unpacker<pack<Ts...>>{using type=pack_cat<pack<>,unpack<Ts>...>;};


                                To test it:



                                pack<int,int,int,int>{}=unpack<pack<int,pack<int,pack<int,pack<int>>>>>{};
                                pack<int,int,int>{} = unpack<pack<int,int,int>>{};
                                pack<int,int,int>{} = unpack<pack<pack<int,int>,int>>{};


                                which compile IFF the two types are the same.







                                share|improve this answer












                                share|improve this answer



                                share|improve this answer










                                answered Jan 3 at 16:54









                                Yakk - Adam NevraumontYakk - Adam Nevraumont

                                189k21200385




                                189k21200385























                                    0














                                    template< typename >
                                    struct is_tuple: false_type{};

                                    template<typename ... input_t>
                                    struct is_tuple< std::tuple<input_t ... > > :
                                    true_type{};

                                    template<typename ... input_t> using flat_tuple= decltype(std::tuple_cat( std::declval< std::conditional_t< is_tuple< input_t >::value, input_t, std::tuple< input_t > > >()... ) );





                                    share|improve this answer




























                                      0














                                      template< typename >
                                      struct is_tuple: false_type{};

                                      template<typename ... input_t>
                                      struct is_tuple< std::tuple<input_t ... > > :
                                      true_type{};

                                      template<typename ... input_t> using flat_tuple= decltype(std::tuple_cat( std::declval< std::conditional_t< is_tuple< input_t >::value, input_t, std::tuple< input_t > > >()... ) );





                                      share|improve this answer


























                                        0












                                        0








                                        0







                                        template< typename >
                                        struct is_tuple: false_type{};

                                        template<typename ... input_t>
                                        struct is_tuple< std::tuple<input_t ... > > :
                                        true_type{};

                                        template<typename ... input_t> using flat_tuple= decltype(std::tuple_cat( std::declval< std::conditional_t< is_tuple< input_t >::value, input_t, std::tuple< input_t > > >()... ) );





                                        share|improve this answer













                                        template< typename >
                                        struct is_tuple: false_type{};

                                        template<typename ... input_t>
                                        struct is_tuple< std::tuple<input_t ... > > :
                                        true_type{};

                                        template<typename ... input_t> using flat_tuple= decltype(std::tuple_cat( std::declval< std::conditional_t< is_tuple< input_t >::value, input_t, std::tuple< input_t > > >()... ) );






                                        share|improve this answer












                                        share|improve this answer



                                        share|improve this answer










                                        answered Jan 3 at 17:11









                                        Red.WaveRed.Wave

                                        89537




                                        89537























                                            0














                                            And now... for something completely different... (well... not completely... almost the Holt's solutions but using functions instead of structs)



                                            You can combine std::tuple_cat() with decltype() in a couple of declared function to flat a pack in a std::tuple



                                            template <typename T>
                                            constexpr std::tuple<T> foo (T);

                                            template <typename ... Ts>
                                            constexpr auto foo (pack<Ts...>)
                                            -> decltype( std::tuple_cat(foo(std::declval<Ts>())...) );


                                            and another declared functions that convert the flattened std::tuple again in a pack



                                            template <typename ... Ts>
                                            constexpr pack<Ts...> bar (std::tuple<Ts...>);


                                            Now you can combine in a flattener as follows



                                            template <typename T>
                                            using fl = decltype(bar(foo(std::declval<T>())));


                                            The following is a full compiling example



                                            #include <tuple>
                                            #include <type_traits>

                                            template <typename...>
                                            struct pack
                                            { };

                                            template <typename T>
                                            constexpr std::tuple<T> foo (T);

                                            template <typename ... Ts>
                                            constexpr auto foo (pack<Ts...>)
                                            -> decltype( std::tuple_cat(foo(std::declval<Ts>())...) );

                                            template <typename ... Ts>
                                            constexpr pack<Ts...> bar (std::tuple<Ts...>);

                                            template <typename T>
                                            using fl = decltype(bar(foo(std::declval<T>())));

                                            int main()
                                            {
                                            using U0 = pack<int, pack<int, pack<int, pack<int>>>>;
                                            using U1 = pack<int, int, int, int>;
                                            using U2 = fl<U0>;
                                            using U3 = pack<int, pack<int, long>, pack<pack<int, char>, long>>;
                                            using U4 = pack<int, int, long, int, char, long>;
                                            using U5 = fl<U3>;

                                            static_assert( std::is_same<U1, U2>::value, "!" );
                                            static_assert( std::is_same<U4, U5>::value, "!" );
                                            }





                                            share|improve this answer




























                                              0














                                              And now... for something completely different... (well... not completely... almost the Holt's solutions but using functions instead of structs)



                                              You can combine std::tuple_cat() with decltype() in a couple of declared function to flat a pack in a std::tuple



                                              template <typename T>
                                              constexpr std::tuple<T> foo (T);

                                              template <typename ... Ts>
                                              constexpr auto foo (pack<Ts...>)
                                              -> decltype( std::tuple_cat(foo(std::declval<Ts>())...) );


                                              and another declared functions that convert the flattened std::tuple again in a pack



                                              template <typename ... Ts>
                                              constexpr pack<Ts...> bar (std::tuple<Ts...>);


                                              Now you can combine in a flattener as follows



                                              template <typename T>
                                              using fl = decltype(bar(foo(std::declval<T>())));


                                              The following is a full compiling example



                                              #include <tuple>
                                              #include <type_traits>

                                              template <typename...>
                                              struct pack
                                              { };

                                              template <typename T>
                                              constexpr std::tuple<T> foo (T);

                                              template <typename ... Ts>
                                              constexpr auto foo (pack<Ts...>)
                                              -> decltype( std::tuple_cat(foo(std::declval<Ts>())...) );

                                              template <typename ... Ts>
                                              constexpr pack<Ts...> bar (std::tuple<Ts...>);

                                              template <typename T>
                                              using fl = decltype(bar(foo(std::declval<T>())));

                                              int main()
                                              {
                                              using U0 = pack<int, pack<int, pack<int, pack<int>>>>;
                                              using U1 = pack<int, int, int, int>;
                                              using U2 = fl<U0>;
                                              using U3 = pack<int, pack<int, long>, pack<pack<int, char>, long>>;
                                              using U4 = pack<int, int, long, int, char, long>;
                                              using U5 = fl<U3>;

                                              static_assert( std::is_same<U1, U2>::value, "!" );
                                              static_assert( std::is_same<U4, U5>::value, "!" );
                                              }





                                              share|improve this answer


























                                                0












                                                0








                                                0







                                                And now... for something completely different... (well... not completely... almost the Holt's solutions but using functions instead of structs)



                                                You can combine std::tuple_cat() with decltype() in a couple of declared function to flat a pack in a std::tuple



                                                template <typename T>
                                                constexpr std::tuple<T> foo (T);

                                                template <typename ... Ts>
                                                constexpr auto foo (pack<Ts...>)
                                                -> decltype( std::tuple_cat(foo(std::declval<Ts>())...) );


                                                and another declared functions that convert the flattened std::tuple again in a pack



                                                template <typename ... Ts>
                                                constexpr pack<Ts...> bar (std::tuple<Ts...>);


                                                Now you can combine in a flattener as follows



                                                template <typename T>
                                                using fl = decltype(bar(foo(std::declval<T>())));


                                                The following is a full compiling example



                                                #include <tuple>
                                                #include <type_traits>

                                                template <typename...>
                                                struct pack
                                                { };

                                                template <typename T>
                                                constexpr std::tuple<T> foo (T);

                                                template <typename ... Ts>
                                                constexpr auto foo (pack<Ts...>)
                                                -> decltype( std::tuple_cat(foo(std::declval<Ts>())...) );

                                                template <typename ... Ts>
                                                constexpr pack<Ts...> bar (std::tuple<Ts...>);

                                                template <typename T>
                                                using fl = decltype(bar(foo(std::declval<T>())));

                                                int main()
                                                {
                                                using U0 = pack<int, pack<int, pack<int, pack<int>>>>;
                                                using U1 = pack<int, int, int, int>;
                                                using U2 = fl<U0>;
                                                using U3 = pack<int, pack<int, long>, pack<pack<int, char>, long>>;
                                                using U4 = pack<int, int, long, int, char, long>;
                                                using U5 = fl<U3>;

                                                static_assert( std::is_same<U1, U2>::value, "!" );
                                                static_assert( std::is_same<U4, U5>::value, "!" );
                                                }





                                                share|improve this answer













                                                And now... for something completely different... (well... not completely... almost the Holt's solutions but using functions instead of structs)



                                                You can combine std::tuple_cat() with decltype() in a couple of declared function to flat a pack in a std::tuple



                                                template <typename T>
                                                constexpr std::tuple<T> foo (T);

                                                template <typename ... Ts>
                                                constexpr auto foo (pack<Ts...>)
                                                -> decltype( std::tuple_cat(foo(std::declval<Ts>())...) );


                                                and another declared functions that convert the flattened std::tuple again in a pack



                                                template <typename ... Ts>
                                                constexpr pack<Ts...> bar (std::tuple<Ts...>);


                                                Now you can combine in a flattener as follows



                                                template <typename T>
                                                using fl = decltype(bar(foo(std::declval<T>())));


                                                The following is a full compiling example



                                                #include <tuple>
                                                #include <type_traits>

                                                template <typename...>
                                                struct pack
                                                { };

                                                template <typename T>
                                                constexpr std::tuple<T> foo (T);

                                                template <typename ... Ts>
                                                constexpr auto foo (pack<Ts...>)
                                                -> decltype( std::tuple_cat(foo(std::declval<Ts>())...) );

                                                template <typename ... Ts>
                                                constexpr pack<Ts...> bar (std::tuple<Ts...>);

                                                template <typename T>
                                                using fl = decltype(bar(foo(std::declval<T>())));

                                                int main()
                                                {
                                                using U0 = pack<int, pack<int, pack<int, pack<int>>>>;
                                                using U1 = pack<int, int, int, int>;
                                                using U2 = fl<U0>;
                                                using U3 = pack<int, pack<int, long>, pack<pack<int, char>, long>>;
                                                using U4 = pack<int, int, long, int, char, long>;
                                                using U5 = fl<U3>;

                                                static_assert( std::is_same<U1, U2>::value, "!" );
                                                static_assert( std::is_same<U4, U5>::value, "!" );
                                                }






                                                share|improve this answer












                                                share|improve this answer



                                                share|improve this answer










                                                answered Jan 3 at 20:15









                                                max66max66

                                                39.4k74575




                                                39.4k74575






























                                                    draft saved

                                                    draft discarded




















































                                                    Thanks for contributing an answer to Stack Overflow!


                                                    • Please be sure to answer the question. Provide details and share your research!

                                                    But avoid



                                                    • Asking for help, clarification, or responding to other answers.

                                                    • Making statements based on opinion; back them up with references or personal experience.


                                                    To learn more, see our tips on writing great answers.




                                                    draft saved


                                                    draft discarded














                                                    StackExchange.ready(
                                                    function () {
                                                    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54025813%2fhow-to-flatten-nested-templates-parameters%23new-answer', 'question_page');
                                                    }
                                                    );

                                                    Post as a guest















                                                    Required, but never shown





















































                                                    Required, but never shown














                                                    Required, but never shown












                                                    Required, but never shown







                                                    Required, but never shown

































                                                    Required, but never shown














                                                    Required, but never shown












                                                    Required, but never shown







                                                    Required, but never shown







                                                    Popular posts from this blog

                                                    MongoDB - Not Authorized To Execute Command

                                                    How to fix TextFormField cause rebuild widget in Flutter

                                                    Npm cannot find a required file even through it is in the searched directory