1
votes

comment aplatir les paramètres des modèles imbriqués?

Disons que j'ai

pack<int, int, int, int>

Je veux convertir

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

en

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

Comment puis-je le faire?


1 commentaires

Voulez-vous également convertir des éléments tels que pack , int> ?


7 Réponses :


2
votes

Une implémentation rapide possible basée sur std :: tuple_cat code> :

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;

Démo Godbolt a >


0 commentaires

1
votes

Je décompresserais et emballerais récursivement les choses:

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...>>;
};

Le type repack >>> > :: type se transforme en:

  • pack >>>>
  • pack >>>
  • pack >>
  • pack

Démo en direct


1 commentaires

Ce code ne génère pas le type que vous pensez qu'il génère. Il ne gère pas non plus `pack à droite.



2
votes

Je propose la structure suivante et en utilisant

#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, "!" );
 }

De cette façon, vous pouvez aplatir pack et d'autres template-template, comme std :: tuple code>, et aussi des exemples plus complexes (le pack , int> suggéré par Holt, par exemple).

Si vous ne voulez que plat pack , en évitant que tous les template-template soient aplatis ..., je veux dire ... si vous voulez que

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

soit aplati comme p>

pack<int, int, int, long>

au lieu de

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

vous devez supprimer le paramètre template-template dans le dernier flatt_helper spécialisation et simplifiez-la comme suit

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

Ce qui suit est un exemple de compilation complet (avec aplatissement complet)

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;


2 commentaires

Bonne réponse avec la construction de pack<> mais vous devez souligner que, avec le paramètre template template, cela aplatira tout, comme flatt >> est en fait pack , ce qui peut ne pas être le comportement attendu ici.


@Holt - oui, ce n'était pas clair; réponse modifiée; l'espoir est plus clair maintenant



0
votes

pack_cat prend une séquence de packs ou de non-packs, et concatine tout ce qui est un pack ensemble, plus les éléments qui ne sont pas des packs.

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>>{};

unpacker prend un pack, décompresse récursivement tous les sous-packs et les concatine.

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>...>;};

Pour le tester:

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...>; };

qui compilent IFF les deux types sont les mêmes.

p>


0 commentaires

0
votes
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 > > >()... ) );

0 commentaires

0
votes

Et maintenant ... pour quelque chose de complètement différent ... (enfin ... pas complètement ... presque les solutions de Holt mais en utilisant des fonctions au lieu de structs)

Vous pouvez combiner std :: tuple_cat ( ) avec decltype () dans un couple de fonction déclarée pour aplatir un pack dans un std::tuple

#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, "!" );
 }

et une autre fonction déclarée qui convertit à nouveau le std :: tuple aplati dans un pack

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


0 commentaires

1
votes

En retard pour la fête?

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>>);


0 commentaires