考虑:
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;}
文章来源: Why doesn't a derived template class have access to a base template class' identifiers?