为什么不是派生模板类可以使用一个基本模板类的标识?
-
11-09-2019 - |
题
考虑:
template <typename T>
class Base
{
public:
static const bool ZEROFILL = true;
static const bool NO_ZEROFILL = false;
}
template <typename T>
class Derived : public Base<T>
{
public:
Derived( bool initZero = NO_ZEROFILL ); // NO_ZEROFILL is not visible
~Derived();
}
我与GCC G ++ 3.4.4(Cygwin的)。
不能编译此在此之前将这些类模板,它们是非通用的和派生类能够看到基类的静态成员。是知名度的这种损失在C ++规范的要求,或是否有语法的变化,我需要使用?
据我所知,Base<T>
的每个实例都会有它自己的静态成员“ZEROFILL
”和“NO_ZEROFILL
”,即Base<float>::ZEROFILL
和Base<double>::ZEROFILL
是不同的变量,但我真的不关心;常量是有代码的可读性。我想用一个静态常量,因为在名称冲突的条款,而不是宏观或全球更加安全。
解决方案
这是给你的两阶段查找。
Base<T>::NO_ZEROFILL
(全部大写标识符是嘘声,除了宏,顺便说一句)是取决于T
的标识符。结果
因为,当编译器首先分析模板,也没有实际的类型T
取代的是,编译器并不“知道”什么是Base<T>
。因此,它可以不知道你承担它被定义的任何标识符(有可能是一些T
s,编译器只是后来看到一个专业化),你不能省略从基类中定义的标识符的基类资格。
这就是为什么你必须写Base<T>::NO_ZEROFILL
(或this->NO_ZEROFILL
)。这告诉NO_ZEROFILL
东西在基类,它依赖于T
,而且它只能稍后再验证它,当模板实例化编译器。因此,它会接受它,但不尝试验证码。结果
该代码只能被后经核实,当模板通过为T
实际参数实例化。
其他提示
您遇到的问题是由于对相关的基类名称查找规则。 14.6 / 8具有:
当寻找一个名称的模板中的定义中使用的声明,通常的查找规则(3.4.1, 3.4.2)用于非依赖的名字。名字依赖于模板参数的查找是 推迟直到实际模板参数是已知的(14.6.2)。
(这不是真正“2阶段查找” - 见下文的那个的解释)
在点约14.6 / 8是尽可能的编译器而言在你的例子NO_ZEROFILL
是一个标识符,并且不依赖于模板参数。因此,它被查找按照一般规则在3.4.1和3.4.2。
此正常查找没有内部Base<T>
搜索等NO_ZEROFILL仅仅是一个未声明的标识符。 14.6.2 / 3具有:
在一个类模板或模板类中的成员的定义,如果一个基类类模板的 依赖于模板的参数,不合格的名称查找期间不检查的基类范围 无论是在类模板或构件或定义的类模板的实例化期间,点 或构件。
当你在本质上与NO_ZEROFILL
资格Base<T>::
你是从一个非从属名称为依赖一个改变它,当你做,你耽误了查找,直到模板实例。
<强>边注:什么是2-阶段查找强>
void bar (int);
template <typename T>
void foo (T const & t) {
bar (t);
}
namespace NS
{
struct A {};
void bar (A const &);
}
int main ()
{
NS::A a;
foo (a);
}
在上面的例子如下编译。编译器解析foo
的功能体和看到,有一个呼叫到bar
具有依赖参数(即,一个是依赖于模板的参数)。此时编译器查找栏按3.4.1,这是“第1阶段查找”。该查找会发现功能void bar (int)
和存储与因呼叫,直到后来。
当模板然后实例化(如从main
呼叫的结果),编译器然后执行在参数的范围的附加的查找,这是在“第2阶段的查找”。这种情况下,其导致在寻找void NS::bar(A const &)
。
编译器有两个重载bar
并在它们之间进行选择,在上述情况下主叫void NS::bar(A const &)
。
看起来编译好的在VS 2008你试过:
public:
Derived( bool initZero = Base<T>::NO_ZEROFILL );
试试这个程序
#include<iostream>
using namespace std;
template <class T> class base{
public:
T x;
base(T a){x=a;}
virtual T get(void){return x;}
};
template <class T>
class derived:public base<T>{
public:
derived(T a):base<T>(a){}
T get(void){return this->x+2;}
};
int main(void){
base<int> ob1(10);
cout<<ob1.get()<<endl;
derived<float> ob(10);
cout<<ob.get();
return 0;
}
在T get(void){return this->x+2;}
系U还可以使用范围分辨率(::)运算符。例如,尝试用替换行
T get(void){return base<T>::x+2;}