[英]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:以下代码段在编译期间会产生“对 foo 的模糊调用”错误,我想知道是否有任何方法可以解决此问题,而无需完全限定对 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;
}
Member lookup rules are defined in Section 10.2/2成员查找规则在第 10.2/2 节中定义
The following steps define the result of name lookup in a class scope,
C
.以下步骤定义类范围C
中名称查找的结果。 First, every declaration for the name in the class and in each of its base class sub-objects is considered.首先,考虑类及其每个基类子对象中名称的每个声明。 A member namef
in one sub-objectB
hides a member namef
in a sub-objectA
ifA
is a base class sub-object ofB
.成员名称f
在一个子对象B
兽皮的成员名f
在一个子对象A
如果A
是一个基类的子对象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 ofC
that is of the type containing the declara-tion designated by the using-declaration.通过 using 声明引入的这些声明中的每一个都被认为来自C
每个子对象,这些子对象属于包含 using 声明指定的声明的类型。 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所以你可以使用using
声明A::f
和B::f
来解决这种歧义
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.第二个代码完美无缺,因为void foo(float)
在 C 的范围内。 Actually d.foo(5);
实际上d.foo(5);
calls void foo(float)
and not the int
version.调用void foo(float)
而不是int
版本。
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 dD::foo
, or d.B1::foo
, or d.B2::foo
.在这种情况下,我们必须决定d.foo
是指dD::foo
,还是d.B1::foo
,还是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.在您的示例中,如果有这样的函数,调用d.foo()
会找到D::foo()
。 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.现在foo
可以同样查找B1::foo
或B2::foo
所以它是模棱两可的。
For the same reason, you would get ambiguity calling unqualified foo(5);
出于同样的原因,调用不合格的foo(5);
会产生歧义foo(5);
inside a D
member function.在D
成员函数中。
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.是因为这会创建名称D::foo
,并使其标识两个函数。 The result is that d.foo
resolves to dD::foo
, and then overload resolution can happen on these two functions that are identified by D::foo
.结果是d.foo
解析为dD::foo
,然后重载解析可以发生在这两个由D::foo
标识的函数上。
Note: In this example D::foo(int)
and Base1::foo(int)
are two identifiers for the one function;注意:在这个例子中, D::foo(int)
和Base1::foo(int)
是一个函数的两个标识符; 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.但总的来说,对于名称查找和重载解析过程,它们是否是两个单独的函数并没有区别。
Will it work for you?它对你有用吗?
struct Derived : public Base1, public Base2{
using Base2::foo;}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.