Частичная специализация для вариационного шаблона требует сначала невариантного параметра шаблона
Следующий код
#include <iostream>
#include <utility>
template<typename F, typename... T>
struct Wrapper{ };
template<typename T>
struct is_wrapper : std::false_type {};
template<typename... T>
struct is_wrapper<Wrapper<T...>> : std::true_type {};
//template<typename F, typename... T>
//struct is_wrapper<Wrapper<F, T...>> : std::true_type {};
int main()
{
Wrapper<int, double> w;
std::cout << is_wrapper<decltype(w)>::value << std::endl;
}
печатает 0. Однако, если разбить две строки посередине, она печатает 1.
Почему он не всегда печатает 1? Должна ли вторая второстепенная специализация охватывать случай, который, по-видимому, покрывается третьей (прокомментированной) частичной специализацией?
Ответы
Ответ 1
Код действительно должен соответствовать частичной специализации; Стандарт никогда фактически не запрещал это, но компиляторы действительно занимали некоторое время, чтобы реализовать вариативные шаблоны и их вычет должным образом. GCC соответствует с 4.9.0 и Clang по состоянию на 3.6. Соответствующий отчет об ошибке для Clang # 22191 (я не могу найти GCC, хотя).
Ответ 2
Обычно, когда я пишу шаблоны, которые будут специализированными, я сначала использую предварительное объявление и объявляю, что случаи относятся к специализациям. В вашем случае я понимаю, что вы пытаетесь написать вариационный шаблон без пустого пространства (т.е. Вариационный шаблон, который может иметь хотя бы один тип).
Ваш код удивил меня, потому что я думаю, что вы правы, полная вариационная специализация вашей черты соответствует дырочным случаям... Сначала я попытался использовать объявление вперед своего класса признаков и определить ТОЛЬКО полную вариационную специализацию (Итак, если параметр признака не является экземпляром Wrapper
, компиляция не выполняется). И это именно то, что произошло, разочаровало меня снова:
#include <iostream>
#include <utility>
template<typename F , typename... T>
struct Wrapper {};
template<typename T>
struct is_wrapper;
//template<typename T>
//struct is_wrapper : std::false_type {};
template<typename... T>
struct is_wrapper<Wrapper<T...>> : std::true_type {};
//template<typename F, typename... T>
//struct is_wrapper<Wrapper<F, T...>> : std::true_type {};
using my_wrapper_type = Wrapper<int,double>;
int main()
{
std::cout << std::boolalpha << is_wrapper<my_wrapper_type>::value << std::endl;
}//"Invalid use of incomplete type" ^^^^^^^^^^^^^^^^^^^^^^^^^^^
Наконец, я попробовал метод прямого объявления в классе Wrapper
. И удивительно, что он работает:
#include <iostream>
#include <utility>
template<typename... T>
struct Wrapper;
template<typename F, typename... T>
struct Wrapper<F,T...>{ };
template<typename T>
struct is_wrapper : std::false_type {};
template<typename... T>
struct is_wrapper<Wrapper<T...>> : std::true_type {};
//template<typename F, typename... T>
//struct is_wrapper<Wrapper<F, T...>> : std::true_type {};
using my_wrapper_type = Wrapper<int,double>;
int main()
{
std::cout << std::boolalpha << is_wrapper<my_wrapper_type>::value << std::endl;
}
Отпечатки:
True
Здесь - код, запущенный на ideone.
С уважением, я не понимаю, почему ваш код выходит из строя, а мой работает. Его ошибка компилятора, или есть что-то, чего нам не хватает? Я не знаю.
Ответ 3
Если я хорошо понимаю вашу проблему, это просто приоритет специализации,
is_wrapper<decltype(w)>
Может быть специализирован по 2 шаблонам:
template<typename T> // exact specialization
template<typename... T> // variadic specialization with one parameter
В этом случае компилятор выбирает в приоритете точную специализацию, поэтому шаблон никогда не устанавливается в вашем случае.