Конкатенация кортежей как типов - PullRequest
0 голосов
/ 20 ноября 2018

Я пытаюсь попрактиковаться в программировании шаблонов.Может быть, есть стандартный способ сделать это, и я был бы благодарен за такие ответы, но моя главная цель состоит в том, чтобы практиковать методы программирования шаблонов, поэтому я попытался реализовать это сам:

Мне нужно объединить несколько кортежей, но как типы, а не как std::cat_tuple это делает.Поэтому мне нужно что-то вроде cat<std::tuple<int, float>, std::tuple<char, bool>, ...>, чтобы получить std::tuple<int, float, char, bool, ...> как тип.

Моя текущая попытка не удалась с ошибкой is not a template:

/* Concat tuples as types: */
template <typename first_t, typename... rest_t> struct cat {
    using type = typename _cat<first_t, typename cat<rest_t...>::type>::type;
                          ^^^^ cat is not a template
};
template <typename first_t, typename second_t>
struct cat<first_t, second_t> {
    using type = typename _cat<first_t, second_t>::type;
                          ^^^^ cat is not a template
};
// Concat two tuples:
template <typename, typename> struct _cat;
template <typename tuple_t, typename first_t, typename... rest_t>
struct _cat<tuple_t, std::tuple<first_t, rest_t...>> {
    using type = typename _cat<typename append<first_t, tuple_t>::type, std::tuple<rest_t...>>::type;
};
template <typename tuple_t, typename first_t>
struct _cat<tuple_t, std::tuple<first_t>> {
    using type = typename append<first_t, tuple_t>::type;
};
// Prepend element to tuple:
template <typename, typename> struct prepend;
template <typename elem_t, typename... tuple_elem_t>
struct prepend<elem_t, std::tuple<tuple_elem_t...>> {
    using type = std::tuple<elem_t, tuple_elem_t...>;
};
// Apppend element to tuple:
template <typename, typename> struct append;
template <typename elem_t, typename... tuple_elem_t>
struct append<elem_t, std::tuple<tuple_elem_t...>> {
    using type = std::tuple<tuple_elem_t..., elem_t>;
};

Что может быть причиной ошибки?

Это хороший подход?Это может быть решено более простым способом, но я хотел, чтобы он был многоцелевым (с операциями добавления / добавления и т. Д.).

Ответы [ 3 ]

0 голосов
/ 20 ноября 2018

Слишком поздно играть?

Я предлагаю следующее решение

template <typename T, typename ...>
struct cat
 { using type = T; };

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

Обратите внимание, что это решение работает не только с вариационным списком std::tuple, но и суниверсальный контейнер типов.Если вам достаточно только std::tuple решения, вы можете упростить его следующим образом:

template <typename T, typename ...>
struct cat
 { using type = T; };

template <typename ... Ts1, typename ... Ts2, typename ... Ts3>
struct cat<std::tuple<Ts1...>, std::tuple<Ts2...>, Ts3...>
   : public cat<std::tuple<Ts1..., Ts2...>, Ts3...>
 { };

Вы можете протестировать работу с

   using t1 = typename cat<std::tuple<int, float>,
                           std::tuple<char, bool>,
                           std::tuple<long, char, double>>::type;

   using t2 = std::tuple<int, float, char, bool, long, char, double>;

   static_assert(std::is_same<t1, t2>::value, "!");

- РЕДАКТИРОВАТЬ --

Как указано felix (спасибо!) С моим прецедентным решением, мы имеем, что

std::is_same<int, typename cat<int>::type>::value == true

, то есть ... cat<T>::type определяется также, когда T не std::tuple.

Это проблема?

Я не знаю, потому что я не знаю, как используется cat<T>::type.

Во всяком случае ... избегайте того, чтобы cat<Ts...>::type определялось только тогда, когда все Ts... являются контейнерами типа (с одним и тем же контейнером), это просто: основная версия для cat становится только объявленной, но не определенной

template <typename, typename ...> // or also template <typename...>
struct cat;

и вводится дополнительная специализация с одним типом (но только если это контейнер типов).

template <template <typename ...> class C, typename ... Ts1>
struct cat<C<Ts1...>>
 { using type = C<Ts1...>; };
0 голосов
/ 20 ноября 2018

Как насчет однострочного прямого псевдонима шаблона:

template<typename ... input_t>
using tuple_cat_t=
decltype(std::tuple_cat(
    std::declval<input_t>()...
));


tuple_cat_t<
    std::tuple<int,float>,
    std::tuple<int>
    > test{1,1.0f,2};
0 голосов
/ 20 ноября 2018

После переупорядочения определения немного, ваш код работает нормально.

Я не думаю, что есть какие-либо рекомендации для шаблонного метапрограммирования.Вероятно, из-за того, что комитет C ++ "агрессивно" продвигает TMP, и слишком мало людей используют TMP.

Вот моя версия Cat, она в основном соответствует той же структуре, что и ваша:

template <class, class>
struct Cat;
template <class... First, class... Second>
struct Cat<std::tuple<First...>, std::tuple<Second...>> {
    using type = std::tuple<First..., Second...>;
};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...