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;
}

Why is multiply inheriting a method with different signatures ambiguous? [duplicate]

This question already has an answer here: Why do multiple-inherited functions with same name but different signatures not get treated as overloaded functions? 2 answers If I inherit a function

Why can’t GCC disambiguate multiple inherited functions (yet clang can)? [duplicate]

Possible Duplicate: Why do multiple-inherited functions with same name but different signatures not get treated as overloaded functions? This fails to compile in the indicated place with g++ 4.6.1:

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 <

Polymorphism and overloaded functions with different signatures

What I want to do : a simple storage class, defined as a template to be as general as possible. And being able to derive from this class another, that would accept anything, convert it to int (the alg

Why does Haskell hide functions with the same name but different type signatures?

Suppose I was to define (+) on Strings but not by giving an instance of Num String. Why does Haskell now hide Nums (+) function? After all, the function I have provided: (+) :: String -> String -&g

same functions name in different pages

I have some ASP pages and sometimes different pages have same name functions. I don’t get why those functions react randomly (not executing, error saying is already defined,etc.) if I only <!– #in

Why do I get an error when I declare 2 methods with the same name but different signatures?

In the following script I declare two methods with the same name calculate but different signatures. But I get an error on declaration: Fatal error: Cannot redeclare Tester::calculate() in /opt/lampp

AS3: two functions with the same name but incompatible signatures from two interfaces

I have two interfaces that declare functions with the same name but incompatible signatures: interface IDog { function bark() : void; } interface IAdvancedDog { function bark(volume : Number) : void;

Binding functions with different signatures

If this question has been asked, I apologize. I thought you couldn’t bind functions with a different signature, but look at this: void TakesChar(char parameter) { std::cout << parameter <&lt

Register C functions of the same signatures in Lua

Suppose we have many C functions of the same signatures and we want to register them to Lua. For example, each function looks like this one: void foo(int n) { // do some work } We can register each o

Answers

Will it work for you?

struct Derived : public Base1, public Base2{
   using Base2::foo;}

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.

Name lookup is a separate phase to overload resolution.

Name lookup occurs first. That is the process of deciding which scope the name applies to. In this case we must decide whether d.foo means d.D::foo, or d.B1::foo, or d.B2::foo. The name lookup rules do not take into account function parameters or anything; it is purely about names and scopes.

Only once that decision has been made, do we then perform overload resolution on the different overloads of the function in the scope where the name was found.

In your example, calling d.foo() would find D::foo() if there were such a function. But there is none. So, working backwards up the scopes, it tries the base classes. Now foo could equally look up to B1::foo or B2::foo so it is ambiguous.

For the same reason, you would get ambiguity calling unqualified foo(5); inside a D member function.


The effect of the recommended solution:

struct Derived : public Base1, public Base2{
    using Base1::foo;
    using Base2::foo;

is that this creates the name D::foo, and makes it identify two functions. The result is that d.foo resolves to d.D::foo, and then overload resolution can happen on these two functions that are identified by D::foo.

Note: In this example D::foo(int) and Base1::foo(int) are two identifiers for the one function; but in general, for the name lookup and overload resolution process, it doesn’t make a difference whether they are two separate functions or not.