La surprise
C'est un subtil Clang bug, profondément enfouis dans la Norme. Le problème est que, dans presque tous les cas, la non-type de modèle arguments peuvent être converties dans le type de modèle de paramètre. E. g. l'expression Int<0>
a int
littérale argument de valeur 0
qui est en cours de conversion vers le type unsigned long long
du paramètre de modèle N
.
14.8.2 argument de Modèle déduction [temp.déduire]/2 2e balle
-- Non-arguments de type doivent correspondre aux types de la correspondante de non-type de
les paramètres de modèle, ou doit être convertible pour les types de la
correspondante de non-type de paramètres comme indiqué dans 14.3.2, sinon
type de déduction échoue.
Depuis votre modèle de classe is_int<T>
a une spécialisation partielle, nous avons besoin de regarder
14.5.5.1 Correspondance de modèle de classe partielle spécialisations [temp.classe.spec.match]
1 Lorsqu'un modèle de classe est utilisé dans un contexte qui nécessite une
instanciation de la classe, il est nécessaire de déterminer si la
l'instanciation est d'être généré à l'aide de la primaire du modèle ou de l'une de
la partielle de spécialisations. Ceci est fait par la correspondance de modèle
les arguments de la classe template de la spécialisation avec le modèle
des listes d'arguments partiels de spécialisations.
2 Une spécialisation partielle correspond à un réel argument de modèle
liste si les arguments de modèle de la spécialisation partielle peut être
en déduit le modèle réel de la liste d'arguments (14.8.2).
Il semblerait donc que nous pouvons procéder à la précédente citation de 14.8.2/2 2ème balle et correspondent à la deuxième spécialisation (bien que dans ce cas encore plus complexe de résolution de surcharge jeu devrait être joué).
La résolution
Cependant, il s'avère (comme mentionné par @DyP dans les commentaires) qu'une autre clause de la Norme annule et remplace ceci:
14.8.2.5 en Déduire des arguments de modèle à partir d'un type [temp.déduire.type]
17 Si, dans la déclaration d'un modèle de fonction avec un non-type de
modèle à paramètre, la non-type de templateparameter est utilisé dans un
expression dans le paramètre de la fonction-liste et, si le correspondant
modèle argument est déduit, le modèle-type d'argument doit correspondre à
le type de modèle à paramètre exactement, sauf que l'
modèle argument déduit à partir d'un tableau lié peut être de n'importe quelle intégrale
type. [ Exemple:
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
}
Le résultat est que la spécialisation partielle de l' is_int
ne peut pas être déduite car elle ne prend pas exactement du même type (unsigned long long
vs long long
) que l' Int
modèle de classe formelle de non-type de paramètre du modèle.
Vous pouvez résoudre ce problème en donnant la non-type de paramètre de modèle N
dans le partiel de la spécialisation de l' is_int
du même type que la non-type de paramètre N
dans le primaire modèle Int
.
template <IntType N>
// ^^^^^^^^
struct is_int<Int<N>> : std::true_type {};
Exemple Vivant.