Why are multi-inherited functions with the same name but with different signatures not considered overloaded functions?

The following snippet generates an “ambigious call to foo” error during compilation, and I would like to know if there is any way around this problem without fully qualifying the call for 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 the question is how the name 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; } 
+44
c ++ scope overloading multiple-inheritance
Mar 20 2018-11-11T00:
source share
3 answers

Member search rules are defined in Section 10.2 / 2

The following steps determine the result of a name search in a class C . First, each declaration for a name in the class and in each of its sub-objects of the base class is considered. The member name f in one subobject B hides the member name f in subobject A if A is a subobject of base class B Any declarations that are so hidden are excluded from consideration . Each of these declarations that was entered using the declaration advertisement is counted from each sub-object C , which is of the type containing the declaration indicated by the declaration announcement. If the result set of declarations is not all of the sub-objects of the same type or the set has a non-static member and includes elements from separate sub-objects, there is ambiguity and the program is poorly formed . Otherwise, this set is the result of a search.

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

So you can use declarations using A::f and B::f to eliminate this ambiguity

 class C : public A, public B { using A::f; using B::f; }; int main() { C c; cf(); // fine } 

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

+42
Mar 20 2018-11-21T00:
source share

Will this work for you?

 struct Derived : public Base1, public Base2{ using Base2::foo;} 
+2
Mar 20 2018-11-11T00:
source share

Searching for a name is a separate phase for resolution overloading.

First, the search for the name begins. This is the process of determining which area this name belongs to. In this case, we must decide whether d.foo means dD::foo , or d.B1::foo , or d.B2::foo . Name search rules do not take into account functional parameters or anything else; these are purely names and domains.

Only after this decision has been made, we then perform overload resolution for various function overloads in the area where the name was found.

In your example, a call to d.foo() will find D::foo() if there was such a function. But they are not there. Thus, working in the opposite direction by regions, he tries the base classes. Now foo can look at B1::foo or B2::foo same way, so it is ambiguous.

For the same reason, you get ambiguity causing unqualified foo(5); inside a member function of D




The effect of the recommended solution:

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

this is that it creates the name D::foo and allows you to identify two functions. As a result, d.foo resolves to dD::foo , and then with these two functions that are identified by D::foo , permission overloading can occur.

Note. In this example, D::foo(int) and Base1::foo(int) are two identifiers for one function; but in general, it does not matter for the process of finding names and handling overloads whether they are two separate functions or not.

+2
Sep 19 '16 at 2:10
source share



All Articles