Написание базового варианта для вариационного шаблона

Я реализую фильтр времени компиляции, который в основном просто берет вектор времени компиляции (переменный пакет аргументов) Enums, перебирает его и пытается найти, включен ли определенный Enum в вектор.

Предположим, у нас есть перечисления:

enum Color
{
  red,
  green,
  purple,
  blue,
  pink,
  yellow
};

И структура excluded_enums, которая представляет собой просто вектор перечислений времени компиляции, который мы хотим исключить:

template <Color... ExcludedValues>
struct exclude_enums
{ };

Затем у нас может быть мета-функция: is_excluded, которая просто возвращает true или false в зависимости от того, находится ли перечисление среди ExcludedValues.

Фактическая реализация линейного поиска во время компиляции через пакет вариативных аргументов кажется довольно простой для реализации:

template <Color Test, Color Head, Color... Tail>
struct is_excluded_impl
{ 
  static const bool value = (Test == Head ? true : is_excluded_impl<
    Test, Tail...>::value);
};

template <Color Test, Color... Tail>
struct is_excluded_impl<Test, Tail...> 
{ 
   static const bool value = false;
};

Проблема в том, что компилятору (GCC 4.7) не нравится мой базовый вариант. Это не удается с:

внутренняя ошибка компилятора: в process_partial_specialization, в cp/pt.c:4414

Сначала я предположил, что это, вероятно, ошибка компилятора, так как вариативные шаблоны в наши дни все еще в новинку. Но эта ветка отчетов об ошибках указывает на то, что сообщение об ошибке не очень полезен, GCC правильно отвергает это, потому что частичная специализация не более специализирована, чем первичный шаблон, потому что он заменяет несколько параметров пакетным расширением.

Итак, я попытался заставить его думать, что базовый случай является более специализированным, включив дополнительный параметр «счетчик», который представляет собой количество аргументов, оставшихся в пакете аргументов с переменным числом аргументов:

template <std::size_t NumArgs, Color Test, Color Head, Color... Tail>
struct is_excluded_impl
{ 
  static const bool value = (Test == Head ? true : is_excluded_impl<sizeof...(Tail), Test, 
    Tail...>::value);
};

template <Color Test, Color... Tail>
struct is_excluded_impl<0, Test, Tail...> 
{ 
   static const bool value = false;
};

Но это не удается с той же ошибкой. Так это ошибка компилятора? Если нет, то как мне написать правильный базовый вариант, который завершает рекурсию шаблона?


person Channel72    schedule 08.09.2013    source источник


Ответы (1)


Вместо этого объявите основной шаблон с одним вариативным пакетом:

template <Color...>
struct is_excluded_impl : std::false_type {};

template <Color Test, Color Head, Color... Tail>
struct is_excluded_impl<Test, Head, Tail...>
{
    static const bool value =
        Head == Test || is_excluded_impl<Test, Tail...>::value;
};
person jrok    schedule 08.09.2013