Étrange erreur avec une surcharge d’opérateur basée sur un modèle

Lorsque je comstack l’extrait suivant, j’obtiens une erreur de compilation avec clang, mais pas avec g ++ / MSVC:

#include  template struct Const { explicit Const(T val) : value(val) {} T value; }; template struct Var { explicit Var(const std::ssortingng &n) : name(n) {} std::ssortingng name; }; template struct Greater { Greater(L lhs, R rhs) : left(lhs), right(rhs) {} L left; R right; }; template Greater<L, Const > operator > (L lhs, int rhs) { return Greater<L, Const >(lhs, Const(rhs)); } template Greater<Const, R> operator > (int lhs, R rhs) { return Greater<Const, R>(Const(lhs), rhs); } Var d("d"); int main() { d > 10; return 0; } 

L’erreur signalée est la suivante:

 error: overloaded 'operator>' must have at least one parameter of class or enumeration type Greater<Const, R> operator > (int lhs, R rhs) { ^ ./val.h:31:24: note: in instantiation of function template specialization 'operator>' requested here Greater<Const, R> operator > (int lhs, R rhs) { ^ 1 error generated. 

qui concerne la fonction opérateur non utilisée. Si, au lieu de cela, j’écris 10> d au lieu de d> 10, j’obtiens la même erreur à propos de l’autre opérateur> fonction. Ce qui précède comstack bien sous gcc 4.4.6 et VS2012. Quelle est mon erreur?

Je vous remercie.

Clang est correct: la surcharge de l’opérateur nécessite au moins un paramètre de type class ou enum, sinon le programme est mal formé (13.5 / 1). Pour voir pourquoi cette erreur apparaît même, nous devons parsingr un jargon juridique plus standard.

Rappelez-vous la Sainte Trinité de la recherche de noms, de la déduction des arguments et de la résolution de surcharge. La première étape trouve deux operator> surchargés operator> . La deuxième étape déduit les arguments de modèle pour chaque version. Vous pourriez penser que la deuxième surcharge serait victime de la règle SFINAE (14.8.2), de sorte que seul le premier survit à la troisième étape. Cependant, il n’y a pas d’échec de sous-poste (comme dans un exemple de typedef nested manquant), mais une construction illégale (voir 13.5 / 1 mentionné précédemment). Cela même rend le programme mal formé (14.3 / 6)

6 Si l’utilisation d’un argument de modèle donne lieu à une construction mal formée lors de l’instanciation d’une spécialisation de modèle, le programme est mal formé.

Dans 14.8.3, il est mentionné que cette vérification des arguments déduits a lieu avant la résolution de la surcharge, de sorte que votre opérateur préféré n’a aucune chance d’être sélectionné.

En tant que solution de contournement C ++ 03, vous pouvez définir deux operator> amis operator> dans votre modèle de classe Var . Celles-ci seraient injectées dans l’espace de nom environnant (global, dans cet exemple) en tant que fonctions non-modèles avec un paramètre de type classe, de sorte que l’erreur ci-dessus ne devrait pas se produire.

Je dois admettre que je ne sais pas vraiment pourquoi Clang se plaint ici, cela ressemble à un bogue (du compilateur). Btw, Clang 3.3 présente également le problème.

Vous pouvez le supprimer en utilisant SFINAE:

 template typename std::enable_if::value || std::is_enum::value, Greater>>::type operator > (L lhs, int rhs) { return Greater >(lhs, Const(rhs)); } template typename std::enable_if::value || std::is_enum::value, Greater,R>>::type operator > (int lhs, R rhs) { return Greater, R>(Const(lhs), rhs); } 

Cela ressemble à un bogue dans g ++ et VS pour moi. Dans votre exemple, votre type R est int (car l’opérande de droite est int ). Ceci fait alors la signature de la fonction Greater, R> operator > (int lhs, int rhs) qui est la même signature (paramètre) que l’ operator< intégré operator< pour ints . Notez qu'il faut tenir compte des deux modèles (et tenter de déduire les types séparément pour chacun) lors du choix de l' operator> à utiliser: il ne peut pas simplement regarder l'un d'entre eux et décider d'ignorer l'autre.