I would like some light to be shed on a puzzling situation involving ADL, namespaces and operator overloading.
Let Foo be a library which defines a class ( Deriv
) in its own namespace, along with a templated operator *
which returns another class.
namespace Foo {
class Deriv {};
class Another {};
template <typename T>
Another operator* ( T x, const Deriv& d ) { return Another();}
}
Now I use Foo's class in my own library Bar, which defines another operator *
, this time only for float
.
namespace Bar {
typedef Foo::Deriv MyDeriv;
MyDeriv operator* (float x, const MyDeriv& d) { return MyDeriv();}
}
I observe a difference in compiler behaviour depending whether one is inside namespace Bar
or not.
This function (Bar::f1
) compiles, using the second version of the operator *
:
namespace Bar {
void f1() {
Bar::MyDeriv a;
Bar::MyDeriv b = 3.f * a;
}
}
while the same function outside namespace Bar (f2()
) fails to compile, because the compiler attempts only to use Foo::operator*
and cannot guess that it must use Bar::operator*
.
void f2() {
Bar::MyDeriv a;
Bar::MyDeriv b = 3.f * a; // Error : cannot convert Foo:Another to Bar::Myderiv
}
You can see the code live here :http://ideone.com/pkPeOY
Now, if Foo::operator*
was not templated and defined as Foo::operator*(float, const Deriv& d);
then both functions fail to compile with the same error (ambiguous operator overload), as can be seen here : http://ideone.com/wi1EWS
So, facing this situation, this is what is puzzling me
In the templated case, when compiling
f2
, the compiler considers usingFoo::operator*
but notBar::operator*
, while in the non-templated case, it considers using both (and refuses to go further because of the ambiguity). What makes the compiler behave differently ?A user of my library Bar will be outside the
Bar::
namespace, yet I wantBar::operator*
to be used, and notFoo::operator*
. I considered explicitely callingBar::operator*(3.f,a)
, which is ugly, or inserting my own operator in the global namespace, which I reckon is a Bad Thing. Is there an option I am missing, or am I doing something wrong ?