Je souhaiterais que l'on mette un peu de lumière sur une situation embarrassante impliquant l'ADL, les espaces de noms et la surcharge de l'opérateur.Surcharge de l'opérateur, résolution des noms et espaces de noms
Soit Foo une bibliothèque qui définit une classe (Deriv
) dans son propre espace de noms, avec un operator *
qui retourne une autre basé sur un modèle de classe.
namespace Foo {
class Deriv {};
class Another {};
template <typename T>
Another operator* (T x, const Deriv& d) { return Another();}
}
Maintenant j'utilise la classe de Foo dans ma propre bibliothèque Bar, qui définit une autre operator *
, cette fois seulement pour float
.
namespace Bar {
typedef Foo::Deriv MyDeriv;
MyDeriv operator* (float x, const MyDeriv& d) { return MyDeriv();}
}
j'observe une différence de comportement du compilateur selon que l'on est à l'intérieur namespace Bar
ou non.
Cette fonction (Bar::f1
) compile, en utilisant la deuxième version du operator *
:
namespace Bar {
void f1() {
Bar::MyDeriv a;
Bar::MyDeriv b = 3.f * a;
}
}
tandis que la même fonction en dehors de l'espace de noms Bar (f2()
) ne parvient pas à compiler, parce que les tentatives du compilateur que d'utiliser Foo::operator*
et ne peut pas devinez qu'il doit utiliser Bar::operator*
.
void f2() {
Bar::MyDeriv a;
Bar::MyDeriv b = 3.f * a; // Error : cannot convert Foo:Another to Bar::Myderiv
}
Vous pouvez voir le code en direct ici: http://ideone.com/pkPeOY
Maintenant, si Foo::operator*
n'a pas été basé sur des modèles et définis comme Foo::operator*(float, const Deriv& d);
puis les deux fonctions ne parviennent pas à compiler avec la même erreur (surcharge de l'opérateur ambigu), comme peut être vu ici: http://ideone.com/wi1EWS
Alors, face à cette situation, voici ce qui me laisse perplexe
Dans le cas basé sur un modèle, lors de la compilation
f2
, le compilateur envisage d'utiliserFoo::operator*
mais pasBar::operator*
, tandis que dans le non- basé sur un modèle, il considère utilisant à la fois (et refuse d'aller plus loin en raison de l'ambiguïté). Qu'est-ce qui fait que le compilateur se comporte différemment?Un utilisateur de ma bibliothèque Bar sera en dehors de l'espace de noms
Bar::
, mais je veuxBar::operator*
à utiliser, et nonFoo::operator*
. J'ai envisagé d'appeler explicitementBar::operator*(3.f,a)
, ce qui est moche, ou d'insérer mon propre opérateur dans l'espace de noms global, que je suppose être BadThing. Y at-il une option qui me manque, ou est-ce que je fais quelque chose de mal?
@GuyGreer S'il n'y a rien virtuel dans 'Foo :: Deriv ', Je pense qu'il n'y aura aucun inconvénient en termes de taille (et un bon compilateur devrait optimiser tout, je suppose ...). – Holt
Hmm, pour une raison quelconque, je pensais que la classe dérivée devait avoir sa propre adresse ... Je pense que je devrais garder pour moi aujourd'hui, je ne suis pas sur mon jeu. – SirGuy
Yeh désolé de la confusion. Au début, je pensais que c'était parce que Deriv faisait partie d'un CRTP (donc une classe dérivée) mais c'était sans rapport avec le problème, donc j'ai supprimé l'héritage (mais j'ai gardé le nom, ce qui peut être déroutant). – Louen