Spécialisation du modèle de classe: classement partiel et synthèse de fonction

Les règles pour choisir quelle spécialisation de modèle de classe est préférable impliquent de réécrire les spécialisations dans des modèles de fonction et de déterminer quel modèle de fonction est plus spécialisé via les règles de classement pour les modèles de fonction [temp.class.order]. Considérez cet exemple, alors:

#include  template  struct voider { using type = void; }; template  using void_t = typename voider::type; template  struct A { }; template  int foo(A<T, void_t> ) { return 1; } template  int foo(A ) { return 2; } int main() { std::cout << foo(A{}); } 

Les deux gcc et clang imprimer 2 ici. Cela a du sens avec certains exemples précédents – la déduction contre un contexte non déduit ( void contre void_t ) est simplement ignorée, donc déduire <T, void_t> contre réussit mais déduit contre <Y, void_t> échoue dans les deux arguments. Bien.

Considérons maintenant cette généralisation:

 #include  template  struct voider { using type = void; }; template  using void_t = typename voider::type; template  struct int_ { static constexpr int value = I; }; template  struct A : int_ { }; template  struct A<T, void_t> : int_ { }; template  struct A : int_ { }; int main() { std::cout << A::value << '\n'; } 

Clang et gcc signalent cette spécialisation comme étant ambiguë, entre 1 et 2 . Mais pourquoi? Les modèles de fonctions synthétisés ne sont pas ambigus. Quelle est la différence entre ces deux cas?

Clang est compatible avec GCC (et compatible avec le code existant qui dépend de ces deux comportements).

Considérez [temp.deduct.type] p1 :

[…] une tentative est faite pour trouver des valeurs d’argument de modèle (un type pour un paramètre de type, une valeur pour un paramètre de non-type, ou un modèle pour un paramètre de modèle) qui fera P, après substitution des valeurs déduites (appelez-le A déduit), compatible avec A.

Le nœud du problème est ce que «compatible» signifie ici.

En ordonnant partiellement des modèles de fonction, Clang ne fait que déduire dans les deux sens; Si la déduction réussit dans un sens mais pas dans l’autre, cela suppose que le résultat sera “compatible” et l’utilisera comme résultat de la commande.

En ordonnant partiellement les spécialisations partielles du modèle de classe, cependant, Clang interprète «compatible» comme signifiant «le même». Par conséquent, il considère qu’une spécialisation partielle est plus spécialisée qu’une autre si la substitution des arguments déduits de l’une à l’autre reproduirait la spécialisation partielle d’origine.

Changer l’un de ces deux pour correspondre à l’autre casse des quantités substantielles de code réel. 🙁