因为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 的特化)。T
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;
模板参数的成员A::B
、A::a
和不影响 中名称的绑定
。—<em>结束示例]A::Y
A
Y<A>