Я думаю, что определения шаблонов неверны, в обоих случаях вы запускаете точную рекурсию. Я ожидал бы, что компилятор умрет с некоторым стековым потоком внутри компилятора, но появится другая ошибка ...
Реализация шаблона are_same
variadic может быть:
template <class... Args> // base (optional to declare the template)
struct are_same;
template <class A, class B, class... Args> // recursion
struct are_same<A,B,Args...> {
static const bool value = is_same<A,B>::value && are_same<A,Args...>::value;
};
template <class A, class B> // stop condition
struct are_same<A,B> {
static const bool value = is_same<A,B>::value;
};
Обратите внимание, что на шаге recursion
один аргумент удаляется из списка аргументов, поэтому новая проблема, которую необходимо решить, - это уменьшенная версия оригинала. Этот тип шаблонного метапрограммирования тесно связан с рекурсией, и применяются те же правила, чтобы иметь возможность использовать рекурсию, вам нужно убедиться, что каждый рекурсивный шаг приближает вас к решению. В этом конкретном случае, учитывая список из N потенциально одинаковых типов, каждый шаг сводит проблему к нахождению одинаковых N-1 типов.
В качестве условия остановки (заменив прежнее) вы можете использовать альтернативно вырожденную версию проблемы are_same
:
template <class A>
struct are_same<A> {
static const bool value = true;
};
Что является вырожденным в том смысле, что на самом деле не имеет смысла спрашивать, является ли один тип * are_same *, но для различных задач метапрограммирования это может быть уместным.
Другой потенциально более эффективный алгоритм (я не уверен, что компилятор избежит создания шаблона на шаге рекурсии выше), который не зависит от is_same
, может быть:
template <class... Args>
struct are_same;
template <class A, class... Args>
struct are_same<A,A,Args...> { // recursion
static const bool value = are_same<A,Args...>::value;
};
template <class A, class B, class... Args>
struct are_same<A,B,Args...> { // cut, A and B are not the same
static const bool value = false;
};
template <class A>
struct are_same<A> { // end of recursion
static const bool value = true;
};
В этом случае компилятор предпочтет шаги recursion
вместо cut
, когда оба типа совпадают, поэтому нам не нужно проверять is_same
внутри. В то же время, если компилятор перейдет к шагу cut
, нам не нужно обрабатывать оставшуюся часть списка типов, поскольку мы уже знаем ответ.