15

下面的代码给了我一个编译错误'value' is not declared in this scope

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

template <class T>
struct Derived : public Base<T> {
    int getValue() { return value; }
};

我觉得非常奇怪

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

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

4

1 回答 1

20

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

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

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

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

return Base<T>::value;

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

对于从 派生的问题Base<std::string>,编译器可以立即去查找是否Base<std::string>包含一个名为的数据成员value(因为它不依赖于任何模板参数),如果是这样,它将能够确定表达式是好的——形成。

但是,如果您的基类是Base<T>,在T名称查找的第一阶段是未知的,则编译器无法分辨是什么value(甚至可能根本没有Base针对不同s 的特化)。Tvalue

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;

模板参数的成员A::BA::a和不影响 中名称的绑定 。—<em>结束示例]A::YAY<A>

于 2013-04-04T14:22:54.410 回答