Ответ 1
Удивление
Это тонкая ошибка Кланга, глубоко похороненная в Стандарте. Проблема состоит в том, что почти во всех случаях аргументы шаблона без типа могут быть преобразованы в тип параметра шаблона. Например. выражение Int<0>
имеет логический аргумент int
значения 0
, который преобразуется в тип unsigned long long
параметра шаблона N
.
14.8.2 Вывод аргумента шаблона [temp.deduct]/2 2nd bullet
- Аргументы не-типа должны соответствовать типам соответствующего не-типа параметры шаблона, или должны быть конвертированы в типы соответствующих непиговым параметрам, как указано в 14.3.2, в противном случае вывод типа не выполняется.
Поскольку ваш шаблон шаблона is_int<T>
имеет частичную специализацию, нам нужно посмотреть
14.5.5.1 Соответствие частичных специализаций шаблона шаблона [temp.class.spec.match]
1 Когда шаблон шаблона используется в контексте, который требует создания класса, необходимо определить, создание экземпляра должно быть сгенерировано с использованием первичного шаблона или одного из частичные специализации. Это делается путем сопоставления шаблона аргументы специализации шаблона класса с шаблоном список аргументов частичных специализаций.
2 Частичная специализация соответствует заданному фактическому аргументу шаблона если аргументы шаблона частичной специализации могут быть выведенный из фактического списка аргументов шаблона (14.8.2).
Итак, мы можем перейти к более ранней цитате 14.8.2/2 2nd bullet и соответствовать второй специализации (хотя в этом случае нужно будет играть еще более сложную игру с разрешением перегрузки).
Разрешение
Однако, оказывается (как упоминалось в комментариях @DyP в комментариях), что другое предложение в Стандарте заменяет это:
14.8.2.5 Вывод шаблонных аргументов из типа [temp.deduct.type]
17 Если в объявлении шаблона функции с не-типом шаблон-параметр, шаблонный шаблонный шаблон не используется выражение в списке параметров функции и, если соответствующий выводится шаблон-аргумент, тип шаблона-аргумента должен совпадать тип параметра шаблона точно, за исключением того, что a шаблон-аргумент, выведенный из привязки массива, может быть любого интеграла тип. [Пример:
template<int i> class A { / ... / };
template<short s> void f(A<s>);
void k1() {
A<1> a;
f(a); // error: deduction fails for conversion from int to short
f<1>(a); // OK
}
Результат состоит в том, что неполная специализация is_int
не может быть выведена, поскольку она не принимает точный тип (unsigned long long
vs long long
) в качестве формального шаблона шаблона шаблона int
.
Вы можете решить эту проблему, указав параметр N
непигового шаблона <частичного специализации is_int
того же типа, что и непиковый параметр N
в основном шаблоне int
.
template <IntType N>
// ^^^^^^^^
struct is_int<Int<N>> : std::true_type {};