两个超类具有相同名称但不同签名的成员函数时不明确

Fab*_*era 27 c++ templates class-hierarchy

struct A {
    void f(int x) {}
};

struct B {
    template<typename T> void f(T x) {}
};

struct C : public A, public B {};

struct D {
    void f(int x){}
    template<typename T> void f(T x) {} 
};


int main(int argc, char **argv) {
    C c;
    c.f<int>(3);
    D d;
    d.f<int>(3);
}
Run Code Online (Sandbox Code Playgroud)

呼叫d.f是好的原因是什么,但是c.f给出了

error: request for member ‘f’ is ambiguous
error: candidates are: template<class T> void B::f(T)
error:                 void A::f(int)
Run Code Online (Sandbox Code Playgroud)

Joh*_*ren 11

第一部分是由于成员名称查找,这就是它失败的原因.

我会推荐你​​: 10.2/2 Member name lookup

以下步骤在类范围C中定义名称查找的结果.首先,考虑类中及其每个基类子对象中的名称的每个声明.如果A是B的基类子对象,则一个子对象B中的成员名称f隐藏子对象A中的成员名称f.任何如此隐藏的声明都将被排除在考虑范围之外.由using声明引入的每个声明都被认为来自C的每个子对象,该子对象的类型包含using声明指定的声明.

如果生成的声明集不是来自相同类型的子对象,或者集合具有非静态成员并且包括来自不同子对象的成员,则存在歧义并且程序格式错误.否则该集合是查找的结果.

现在,关于模板功能的问题.

按照 13.3.1/7 Candidate functions and argument list

在候选者是函数模板的每种情况下,使用模板参数推导(14.8.3,14.8.2)生成候选函数模板特化.然后以通常的方式将这些候选人作为候选职能处理.给定名称可以引用一个或多个函数模板,也可以引用一组重载的非模板函数.在这种情况下,从每个功能模板生成的候选函数与该组非模板候选函数组合.

如果你继续阅读 13.3.3/1 Best viable function

如果出现以下情况,F1被认为是更好的功能:

F1是非模板函数,F2是函数模板特化

这就是为什么以下代码片段编译并运行非模板函数而没有错误:

D c;
c.f(1);
Run Code Online (Sandbox Code Playgroud)