基类模板的成员超出派生类模板中具有相同模板参数的作用域
问题描述:
以下代码给我一个编译错误'value'未在此范围中声明。基类模板的成员超出派生类模板中具有相同模板参数的作用域
template<class T>
struct Base {
int value;
};
template <class T>
struct Derived : public Base<T> {
int getValue() { return value; }
};
我觉得非常奇怪,
- 如果从
Base<std::string>
Derived
继承,代码编译, - 如果我
return Base<T>::value
,代码编译。
为什么不代码编译器吗?以何种方式是“价值”并不在Derived<T>::getValue()
的范围内声明?
答
因为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
针对不同T
小号特甚至可能没有value
在所有) 。
段落14.6/C++的11标准的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
,和模板参数A
的A::Y
不影响Y<A>
名称的结合。 - 结束示例]
优秀的答案。 – Oswald 2013-04-04 14:39:15
@Oswald:谢谢,很高兴我能帮到 – 2013-04-04 14:40:54
非常好,我可以随时添加:)。 – 2013-04-04 15:04:05