简体   繁体   中英

Operator overloading, name resolution and namespaces

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 using Foo::operator* but not Bar::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 want Bar::operator* to be used, and not Foo::operator* . I considered explicitely calling Bar::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 ?

In the templated case, when compiling f2 , the compiler considers using Foo::operator* but not Bar::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 ?

In both cases the compiler considers using both, but in the case of a templated operator* , the call is not ambiguous since there is a non-templated function which parameter types perfectly matches the arguments (try replace 3.f with 3. and you will see that the templated version is found). Typically:

template <typename T>
void g (T) { }

void g (float) { }

g(0.f); // Ok, the overload for float is preferred over the templated version

A user of my library Bar will be outside the Bar:: namespace, yet I want Bar::operator* to be used, and not Foo::operator*. I considered explicitely calling Bar::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 ?

Unfortunately, ADL will not find your overload since the only parameters of operator* are float and MyDeriv which are defined inside the namespace Foo . One possible way would be to inherit from Foo::Deriv :

namespace Bar {
    struct MyDeriv: public Foo::Deriv {};
    MyDeriv operator* (float x, const MyDeriv& d) { return MyDeriv();}
}

Another one is to declare your overload for operator* inside the Foo namespace:

namespace Bar {
    typedef Foo::Deriv MyDeriv;
}

namespace Foo {
    Bar::MyDeriv operator* (float x, const Bar::MyDeriv& d) { return Bar::MyDeriv(); }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM