Xeo Xeo - 2 months ago 4
C++ Question

Why do multiple-inherited functions with same name but different signatures not get treated as overloaded functions?

The following snippet produces an "ambigious call to foo" error during compilation, and I'd like to know if there is any way around this problem without fully qualifying the call to foo:

#include <iostream>

struct Base1{
void foo(int){
}
};

struct Base2{
void foo(float){
}
};

struct Derived : public Base1, public Base2{
};

int main(){
Derived d;
d.foo(5);

std::cin.get();
return 0;
}


So, question is as the title says. Ideas? I mean, the following works flawlessly:

#include <iostream>

struct Base{
void foo(int){
}
};

struct Derived : public Base{
void foo(float){
}
};

int main(){
Derived d;
d.foo(5);

std::cin.get();
return 0;
}

Answer

Member lookup rules are defined in Section 10.2/2

The following steps define the result of name lookup in a class scope, C. First, every declaration for the name in the class and in each of its base class sub-objects is considered. A member name f in one sub-object B hides a member name f in a sub-object A if A is a base class sub-object of B. Any declarations that are so hidden are eliminated from consideration. Each of these declarations that was introduced by a using-declaration is considered to be from each sub-object of C that is of the type containing the declara-tion designated by the using-declaration. If the resulting set of declarations are not all from sub-objects of the same type, or the set has a nonstatic member and includes members from distinct sub-objects, there is an ambiguity and the program is ill-formed. Otherwise that set is the result of the lookup.

class A {
public:
  int f(int);

};
class B {
public:
   int f();

};
class C : public A, public B {};
int main()
{
     C c;
     c.f(); // ambiguous
}

So you can use the using declarations A::f and B::f to resolve that ambiguity

class C : public A, public B {
     using A::f;
     using B::f;

};

int main()
{
     C c;
     c.f(); // fine
}

The second code works flawlessly because void foo(float) is inside C's scope. Actually d.foo(5); calls void foo(float) and not the int version.