как сгладить параметры вложенных шаблонов? - PullRequest
0 голосов
/ 03 января 2019

Скажите, у меня есть

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

Я хочу конвертировать

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

в

pack<int, int, int, int>

Как я могу это сделать?

Ответы [ 7 ]

0 голосов
/ 03 января 2019

А теперь ... для чего-то совершенно другого ... (ну ... не совсем ... почти решения Холта, но с использованием функций вместо структур)

Вы можете объединить std::tuple_cat() с decltype() в паре объявленных функций для преобразования pack в 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>())...) );

и других объявленных функций, которые снова преобразуют сглаженный std::tuple в pack

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

Теперь вы можете объединить в выравнивателе следующим образом

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

Ниже приведен полный пример компиляции

#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, "!" );
 }
0 голосов
/ 04 января 2019

Опоздал на вечеринку?

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 голосов
/ 03 января 2019
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 голосов
/ 03 января 2019

pack_cat принимает последовательность пачек или неупаковок и объединяет все, что является пачкой вместе, плюс предметы, которые не являются пачками.

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 берет пачку и рекурсивнораспаковывает все подпакеты и объединяет их.

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

Чтобы проверить это:

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

, которые компилируют IFF, оба типа одинаковы.

0 голосов
/ 03 января 2019

Я предлагаю следующую структуру и используя

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;

Таким образом, вы можете сгладить pack и другие шаблоны-шаблоны, как std::tuple, а также более сложные примеры (pack<int, pack<int, int>, int>, предложенныйХолт, к примеру).

Если вы хотите только плоскую pack, избегая того, чтобы все шаблоны-шаблоны были сплющены ..., я имею в виду ... если вы хотите, чтобы

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

уплощено как

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

вместо

pack<int, int, int, long>

Вы должны удалить параметр шаблона-шаблона в последней специализации flatt_helper и упростить его следующим образом

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

Ниже приведен пример полной компиляции (с полным выравниванием)

#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, "!" );
 }
0 голосов
/ 03 января 2019

я бы рекурсивно распаковывал и упаковывал вещи обратно:

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

Тип repack<pack<int, pack<int, pack<int, pack<int>>>>>::type преобразуется в:

  • 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>

Демонстрационная версия

0 голосов
/ 03 января 2019

Возможная быстрая реализация на основе 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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...