模板C++中的范围问题

Pra*_*rav 1 c++ templates

这个程序有什么范围问题吗?

#include<iostream>

using namespace std;

template<class Type>
class Base
{
   public:
   Type member;
   Base(Type param): member(param){

   }
};

template<class Type>
class Derived: public Base<Type>
{
    public:               
    Derived(Type param):Base<Type>(param){
     //                       ^
     //                       |_______  Not writing Type here gives error, why?
    }
    void display()
    {
        cout << member; /** ERROR HERE **/
    }
};

int main()
{
   Derived<int> p(5);
   p.display();
   return 0;
}
Run Code Online (Sandbox Code Playgroud)

我收到错误'member' was not declared in this scope.如何解决问题?

sbi*_*sbi 10

你的问题有些令人困惑.起初我以为你base<Type>在成员初始化列表中询问,然后我以为你问的是访问member,然后回到第一个......现在我在想你们两个都问,所以我会回答两个问题.


不写这里的类型给出错误,为什么?

当您使用类模板的名称(my_class_templ)时,它引用的模板不是类型.要将其用作类型,您需要提供模板参数(my_class_templ<int>,my_class_templ<T>).因此,只要需要类型名称(并且包括初始化列表中的基类名称),就需要提供模板参数.

您可以在类模板的定义中省略类模板名称的模板参数列表.例如,可以将复制构造函数声明为

 my_class_templ(const my_class_templ& rhs);
Run Code Online (Sandbox Code Playgroud)

代替

 my_class_templ<T>(const my_class_templ<T>& rhs);
Run Code Online (Sandbox Code Playgroud)

这只是一个小的语法糖,允许你输入更少.

但是,在类模板定义之外,您需要明确说明所有模板参数.派生类也是如此:

my_dervied_class_templ(const my_derived_class_templ& rhs)
 : my_class_templ<T>(rhs)                          // need to spell out <T> here
{
}
Run Code Online (Sandbox Code Playgroud)

我收到错误'member' was not declared in this scope.如何解决问题?

当编译器首先遇到模板时,只有它的定义,编译器还没有看到实例化.编译器不知道在实例化时是否可能存在范围内的模板特化.但是,您可以将模板专门用于Base<T>::member引用其他内容或不完全定义.(比方说,专门化Base<void>没有数据成员.)因此,编译器不得推测成员Base.因此,他们不会被抬头看Derived.

结果是,如果你需要引用其中一个成员Base,你需要告诉编译器你希望有一个Base<T>这样的成员.这是通过完全限定其名称来完成的:Base<Type>::member.

  • 实际上,初始化列表中的基类说明符问题和“成员”问题都有相同的起源。您*可以*省略模板参数列表并找到注入的类名“Base&lt;Type&gt;”(这是一个完美的类型名称)。然而问题是“Base”是非依赖的,因此无法在依赖基类中查找。如果他说 `:Derived::Base(param)` ,这将工作得很好(仅在从 v4.5 开始的 GCC 上,因为他们之前没有正确实现注入类名查找) (2认同)

Pra*_*rav 8

不写这里的类型给出错误,为什么?

如果省略Type,则编译器无法确定Base是基类还是其成员Derived.指定Type确保它Base是模板类[基类].

'member'未在此范围内声明

这与名称查找规则(依赖基类)有关.

C++ 03 [第14.6/8节]说

在查找模板定义中使用的名称声明时,通常的查找规则(3.4.1,3.4.2)用于非依赖名称.依赖于模板参数的名称查找被推迟,直到知道实际模板参数(14.6.2).

现在Section 14.6.2/3

在类模板的定义或类模板的成员中,如果类模板的基类依赖于模板参数,则在类的定义时,在非限定名称查找期间不会检查基类作用域.模板或成员或在类模板或成员的实例化期间.

member 是一个非限定名称,因此不检查基类.

所以你有两个选择.

  1. 使用Memberie的完全限定名称Base<Type>::member
  2. 使用this->member.