10
votes

Erreur étrange avec une surcharge d'opérateur modélisée

Lorsque je compile le snippet suivant, je reçois une erreur de compilateur avec Clang, mais pas avec g ++ / msvc: xxx pré>

L'erreur signalée est la suivante: p>

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


6 commentaires

Il compile également bien avec GCC 4.8.1: ideone.com/wg4yzv (mode C ++ 98) et < un href = "http://ideone.com/8fwowq" rel = "nOfollow noreferrer"> ideone.com/8fwowq (mode C ++ 11). Quelle est votre version de Clang?


@gx_ vient d'essayer 3.1 et 3.2, les deux présentent le problème.


@Bobtfish Merci (dommage qu'il n'y ait pas de "clang en ligne" (plus)). Je m'interroge sur l'exemple très simplifié Ideone.com/0aoOxo ? EDIT: OH Attendez, il y a Clang 3.0 à gcc.godbolt.org :) Et mon exemple simplifié provoque la même erreur. Edit (2): Merci encore. Ressemble à un bug de compilateur ...


Votre exemple simplifié présente la même erreur. Et retirer l'on est incorrect la cause de réussir.


Ou peut-être que ce n'est en fait pas un bug de clang, mais les autres compilateurs sont trop permissives: P d'avance que j'ai lu quelque part que de tels modèles non contraints sont mieux évités (en particulier pour les surcharges de l'opérateur) ... Trouvé: Une proposition modeste: Fixation ADL (Révision 2)


@gx_ My Clang version est la version 3.2 (basée sur LLVM 3.2). C'est le package standard Clang pour Ubuntu 13.04.


3 Réponses :


0
votes

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

Vous pouvez le supprimer à l'aide de SFIAE: P>

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

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


2 commentaires

Malheureusement, je ne peux utiliser que C ++ 03. Correct si je me trompe, mais STD ::ABLE_IF, STD :: IS_Class, etc. sont C ++ 11 constructions afin que je ne puisse pas les utiliser


@John Enable_if est quelques lignes de code que vous pouvez vous écrire, mais IS_Class nécessite une prise en charge du compilateur, vous ne pouvez donc pas l'utiliser sans C ++ 11



0
votes

Ceci ressemble à un bug dans g ++ et vs pour moi. Dans votre exemple, votre type R est int (car l'opérande de droite est int ). Ceci fait ensuite la signature de la fonction plus grand , r> opérateur> (int LHS, inths) qui est la même signature (paramètre) que le code intégré Opérateur << / code> pour Ints . Notez qu'il doit considérer les deux modèles (et tenter de déduire des types séparément pour chaque) lors de la décision de quel opérateur> à utiliser: il ne peut pas simplement regarder l'un d'entre eux et décider d'ignorer l'autre .


2 commentaires

Lorsque vous envisagez les deux modèles, une instanciation de modèle invalide doit être ignorée ou est-ce une erreur?


@John Non, seules les échecs de substitution ne sont pas des erreurs (Sfinae), toute autre construction illégale lors de la déduction des arguments sont des erreurs difficiles. Voir ma réponse pour plus de détails.



7
votes

Clang a raison: la surcharge de l'opérateur nécessite au moins une classe ou un paramètre de type Enum, sinon le programme est mal formé (13.5 / 1). Pour voir pourquoi cette erreur apparaît même, nous devons analyser un peu de légumese plus standard.

Rappelez-vous la Sainte Trinité de la recherche de nom, de la déduction de l'argument et de la résolution de la surcharge. La première étape trouve deux opérateurs surchargé> . La deuxième étape déduit des arguments de modèle pour chaque version. Vous pourriez penser que la deuxième surcharge sera 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 de défaillance de la substtition (comme par exemple, une clé imitée manquante), mais une construction illégale (voir le précédent mentionné 13.5 / 1). Qui elle-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 dans l'instanciation d'une spécialisation de gabarit, le programme est mal formé.

in 14.8.3 Il est mentionné que cette vérification des arguments déduites arrive avant la résolution de la surcharge, votre opérateur préféré n'a aucune chance d'être sélectionné.

En tant que solution C ++ 03, vous pouvez définir deux amis non-modèles opérateur> à l'intérieur de votre var modèle de classe. Celles-ci seraient injectées dans les espaces de noms environnants (globaux, dans cet exemple) en tant que fonctionnalités autres-modèles avec un paramètre de type de classe, de sorte que l'erreur ci-dessus ne doit pas se produire.


2 commentaires

La question de l'OP utilise opérateur> comme exemple mais votre réponse parle de opérateur << / code>, est-ce juste une faute de frappe?


dr2052 et DR1391 Maintenant, rendez-vous à la cliquet de deux manières différentes, mais on dirait que Leurs résolutions n'ont pas encore été mise en œuvre. Bug de clang 13869 est également pertinent.