为什么我必须确定重载模板基类方法的范围

Why must I scope an overloaded template base class method?

本文关键字:基类 类方法 范围 重载 为什么      更新时间:2023-10-16

如果没有基类的作用域,我似乎无法调用基类的方法,这似乎是因为我重载了该方法。如果我不重载该方法,那么编译器不会抱怨。下面是我想做的一个例子:

struct BaseClass {                                                           
  template <typename T> T& foo(T& t) {                               
    return t;                                                                
  }                                                                          
};                                                                           
class ChildClass: public BaseClass {                                         
  public:
  // The presence of this template causes compiler confusion                                                            
  template <class T> T& foo(T& t, int szl) {                        
    return t;                                                                
  }                                                                          
  template <class T> int bar(T& t) {                 
    // But if I scope this as BaseClass::foo(...) it's all good                        
    return foo(t);                                                
  }                                                                          
};                                                                           
int main() {                                                                 
  int t = 1;                                                                 
  ChildClass c;                                                              
  c.bar(t);                                        
}

如果在bar(…)中我调用BaseClass::foo(…),编译器不会抱怨,但我在这里没有看到任何歧义,所以我很困惑为什么我需要这样做。

当编译器试图将函数名与函数匹配时,它分两步进行。在第一步中,它查找与给定名称匹配的所有函数。如果它找到多个函数,它会尝试重载解析的逻辑来找到最佳匹配的函数。

在第一步中,如果编译器在类中找到一个名称,它将停止在基类中查找同名函数。在您的情况下,由于它在ChildClass中找到了foo,因此它将停止在BaseClass中搜索名为foo的函数。但是,唯一匹配的foo与调用不匹配,编译器会报告错误。

如何解决问题:

  1. 使用你在帖子中描述的方法。致电BaseClass::foo(...)

  2. BaseClass中的所有foo纳入ChildClass的范围。

    class ChildClass: public BaseClass {
      public:
      using  BaseClass::foo;
      template <class T> T& foo(int baz, T& t, int szl) {
         return t;
      }
      template <class T> int bar(T& t) {
        return sizeof(foo(1, t)); // Should work.
      }
    };
    

来自C++标准3.3.10第1段:

可以通过中相同名称的显式声明来隐藏名称嵌套的声明性区域或派生类

CCD_ 10掩盖了CCD_ 11的定义。你所需要的只是一个using指令:

class ChildClass: public BaseClass {                                         
  public:
  using BaseClass::foo;
  template <class T> T& foo(int baz, T& t, int szl);                         
};

您需要一个using,如:

using BaseClass::foo;