下面的代码给了我一个编译错误'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段:
在类或类模板的定义中,如果基类依赖于模板参数,则在类模板或成员的定义点或在实例化实例化期间,不会在非限定名称查找期间检查基类作用域.类模板或成员.[...] [ 示例:
Run Code Online (Sandbox Code Playgroud)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和A::Y模板参数A不会影响名称的绑定Y<A>.- 结束例子 ]