C++ C++;:模板化基类的范围?
此代码不编译:C++ C++;:模板化基类的范围?,c++,templates,inheritance,scope,C++,Templates,Inheritance,Scope,此代码不编译: template <typename T> struct B { typedef T type; }; struct D0 : public B<int> { void h(type) { } }; template <typename T> struct D : public B<T> { void f(typename B<T>::type) { } void g(type) {
template <typename T>
struct B {
typedef T type;
};
struct D0 : public B<int> {
void h(type) { }
};
template <typename T>
struct D : public B<T> {
void f(typename B<T>::type) { }
void g(type) { }
};
模板
结构B{
T型;
};
结构D0:公共B{
空h(型){}
};
模板
结构D:公共B{
void f(typename B::type){}
void g(type){}
};
具体地说,虽然
D0::h(type)
和D::f(typename B::type)
编译,但D::g(type)
没有。为什么type
在D
中不可见?显然,这是由于编译器的语义编译阶段顺序造成的。在编译器看来,符号type
不存在于任何作用域中,因为它(尚未)实例化模板,因此它没有实例化D
本身
唯一的解决方法是强制编译器在语义编译的后期阶段解析符号,例如使用
void f(typename B<T>::type) {}
void f(typename B::type){
或者,如果派生类不是模板,但基类是模板,则编译器必须首先解析/实例化/基类,从而避免派生类内部可能出现的任何错误
但如果基和派生都是模板,则情况并非如此,因为编译器将在实例化派生模板类之前在所有已实例化的作用域(例如全局作用域)中查找派生类的符号,如果失败,那么您已经知道
int main(){printf(“%d\n”,argc)会发生什么显然,这是由于编译器的语义编译阶段顺序。在编译器看来,符号type
不存在于任何作用域中,因为它(尚未)实例化模板,因此它没有实例化D
本身
唯一的解决方法是强制编译器在语义编译的后期阶段解析符号,例如使用
void f(typename B<T>::type) {}
void f(typename B::type){
或者,如果派生类不是模板,但基类是模板,则编译器必须首先解析/实例化/基类,从而避免派生类内部可能出现的任何错误
但如果基和派生都是模板,则情况并非如此,因为编译器将在实例化派生模板类之前在所有已实例化的作用域(例如全局作用域)中查找派生类的符号,如果失败,那么您已经知道int main(){printf(“%d\n”,argc)会发生什么
,否?答案可以在两个地方找到。第一个C++11标准草案:
§14.6.2/3
在类模板或类模板成员的定义中,
如果类模板的基类依赖于模板参数,
在非限定名称查找期间,基类作用域未被检查
在类模板或成员的定义点,或
在类模板或成员的实例化过程中。[示例:
这可能会伤到你的头,最好你坐下
在D::g()
中,名称Xyz
和Pqr
不依赖于模板参数
T、 因此它们被称为非独立名称。另一方面,B
依赖于模板参数T
,因此B
称为依赖
名字
规则是:编译器不查找依赖的基类
(如B
)查找非独立名称(如Xyz
或Pqr
)时。作为
结果,编译器甚至不知道它们的存在,更不用说它们的存在了
类型
此时,程序员有时会在它们前面加上B::
,例如:
template<typename T>
class D : public B<T> {
public:
void g()
{
B<T>::Xyz x; // Bad (even though some compilers erroneously (temporarily?) accept it)
B<T>::Pqr y; // Bad (even though some compilers erroneously (temporarily?) accept it)
}
};
答案可以在两个地方找到。第一个是C++11标准草案:
§14.6.2/3
在类模板或类模板成员的定义中,
如果类模板的基类依赖于模板参数,
在非限定名称查找期间,基类作用域未被检查
在类模板或成员的定义点,或
在类模板或成员的实例化过程中。[示例:
这可能会伤到你的头,最好你坐下
在D::g()
中,名称Xyz
和Pqr
不依赖于模板参数
T、 因此它们被称为非独立名称。另一方面,B
依赖于模板参数T
,因此B
称为依赖
名字
规则是:编译器不查找依赖的基类
(如B
)查找非独立名称(如Xyz
或Pqr
)时。作为
结果,编译器甚至不知道它们的存在,更不用说它们的存在了
类型
此时,程序员有时会在它们前面加上B::
,例如:
template<typename T>
class D : public B<T> {
public:
void g()
{
B<T>::Xyz x; // Bad (even though some compilers erroneously (temporarily?) accept it)
B<T>::Pqr y; // Bad (even though some compilers erroneously (temporarily?) accept it)
}
};
template<typename T>
class D : public B<T> {
public:
void g()
{
typename B<T>::Xyz x; // Good
typename B<T>::Pqr y; // Good
}
};