Шаблон метапрограммы для поиска похожих последовательных названий - PullRequest
0 голосов
/ 05 ноября 2018

Я новичок в шаблонном метапрограммировании и пытался создать программу, которая бы обнаружила, если пакет параметров имеет последовательные имена одинаковых типов. Например, <int, int>, <int, char, char> вернет true, а <int,char> и <int, char, int> - нет.

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

template<typename T, typename U>
struct sameTypename{
    enum {value = false};
};

template<typename T>
struct sameTypename<T, T>{
    enum {value = true};
};

template <typename T, typename ...args>
struct consTypename{
    enum {value = (sameTypename<consTypename<args...>, consTypename<args...>>::value)};
};

template <typename T>
struct consTypename<T, T>{
    enum {value = true};
};

template <typename T>
struct consTypename<T>{
    enum {value = false};
};

Ответы [ 3 ]

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

Вариант решения HolyBlackCat.

template <typename ...>
struct has_adjacent_same_types : public std::false_type
 { };

template <typename T0, typename ... Ts>
struct has_adjacent_same_types<T0, T0, Ts...> : public std::true_type
 { };

template <typename T0, typename T1, typename ... Ts>
struct has_adjacent_same_types<T0, T1, Ts...>
   : public has_adjacent_same_types<T1, Ts...>
 { };

Две более простых специализации вместо одной, более сложной.

По существу это то же самое (я полагаю), но я нахожу это немного ясным для чтения и понимания.

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

Я предлагаю также совершенно другое решение, которое использует свертывание шаблонов (поэтому, к сожалению, только C ++ 17 или новее) вместо рекурсии шаблонов.

template <typename...>
struct sae_helper;

template <typename ... Ts, typename ... Us>
struct sae_helper<std::tuple<Ts...>, std::tuple<Us...>>
   : public std::bool_constant<(std::is_same_v<Ts, Us> || ...)>
 { };

template <typename ... Ts>
struct some_adjacent_equal
   : public sae_helper<std::tuple<void, Ts...>, std::tuple<Ts..., void>>
 { };

Если void является возможным типом в списке типов для проверки, то для вызова sae_helper из some_adjacent_equal вместо void необходимо использовать другой тип, очевидно.

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

Если вы можете использовать C ++ 14, вы можете использовать функцию constexpr вместо свертывания шаблона (и тип тега вместо void) следующим образом

template <typename ... Ts, typename ... Us>
constexpr bool sae_helper (std::tuple<Ts...> const &,
                           std::tuple<Us...> const &)
 {
   using unused = bool[];

   bool ret { false };

   (void)unused { true, ret |= std::is_same<Ts, Us>::value... };

   return ret;
 }

struct no_type
 { };

template <typename ... Ts>
struct some_adjacent_equal
   : public std::integral_constant<bool, sae_helper(std::tuple<no_type, Ts...>{},
                                                    std::tuple<Ts..., no_type>{})>
 { };

но, таким образом, вы теряете короткое замыкание или оценку.

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

Вот, пожалуйста:

#include <type_traits>

template <typename ...P> struct has_adjacent_same_types : std::false_type {};
template <typename A, typename B, typename ...P> struct has_adjacent_same_types<A, B, P...>
    : std::bool_constant<std::is_same_v<A,B> || has_adjacent_same_types<B, P...>::value> {};

Я использовал : std::false_type {}; и : std::bool_constant<X> {}; вместо
{enum{value = false};}; и {enum{value = X};}; соответственно, но это просто вопрос предпочтений.


Некоторые из функций, которые я использовал, взяты из C ++ 17. Если вы используете более старую версию, обратите внимание, что:

std::bool_constant и std::is_same_v доступны только начиная с C ++ 17 (но вы можете использовать std::integral_constant и std::is_same<>::value раньше).

(с) @ max66

...