基类模板的成员超出了具有相同模板参数的派生类模板的范围

Osw*_*ald 15 c++ templates

下面的代码给了我一个编译错误'value'未在此范围内声明.

template<class T>
struct Base {
    int value;
};

template <class T>
struct Derived : public Base<T> {
    int getValue() { return value; }
};
Run Code Online (Sandbox Code Playgroud)

我觉得这很奇怪

  • 如果Derived继承自Base<std::string>,代码编译,
  • 如果我return Base<T>::value,代码编译.

为什么代码不能按原样编译?以什么方式'价值'没有在范围内宣布Derived<T>::getValue()

And*_*owl 20

因为value是一个不合格的名称,并且在名称查找的第一阶段,编译器将不知道这是从基类继承的数据成员(它还没有实例化Base<T>).因此,它将搜索全局命名空间,并找不到调用的变量value; 因此,它会发出错误.

以下是解决此问题的典型方法:

template <class T>
struct Derived : public Base<T> {
    int getValue() { return this->value; }
    //                      ^^^^^^
};
Run Code Online (Sandbox Code Playgroud)

显式解除引用会this告诉编译器,后面的名称是(可能是继承的)数据成员的名称,并且查找应该延迟到实际实例化成员函数的位置.当然,你做的解决方案:

return Base<T>::value;
Run Code Online (Sandbox Code Playgroud)

同样好,因为它还告诉编译器value继承自基类Base<T>.

对于源于Base<std::string>此的问题,编译器可以立即查找是否Base<std::string>包含名为的数据成员value(因为它不依赖于任何模板参数),如果是这种情况,它将能够确定表达式是否良好 -形成.

但是,如果您的基类是Base<T>,在T名称查找的第一阶段未知的地方,编译器无法分辨出什么value是(Base不同的Ts的特化可能根本没有value).

C++ 11标准第14.6/3段:

在类或类模板的定义中,如果基类依赖于模板参数,则在类模板或成员的定义点或在实例化实例化期间,不会在非限定名称查找期间检查基类作用域.类模板或成员.[...] [ 示例:

struct A {
    struct B { / ... / };
    int a;
    int Y;
};

int a;

  template<class T> struct Y : T {
    struct B { / ... / };
    B b; // The B defined in Y
    void f(int i) { a = i; } // ::a
    Y* p; // Y<T>
  };

Y<A> ya;
Run Code Online (Sandbox Code Playgroud)

成员A::B,A::aA::Y模板参数A不会影响名称的绑定 Y<A>.- 结束例子 ]