Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ C++;:模板化基类的范围?_C++_Templates_Inheritance_Scope - Fatal编程技术网

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
  }
};