为什么派生的模板类不能访问基本模板类的标识符?

考虑:

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>::ZEROFILLBase<double>::ZEROFILL是不同的变量,但我并不在乎; 该常量用于代码的可读性。 我想使用静态常量,因为就名称冲突而言,这比使用宏或全局方法更安全。

cheshirekow asked 2020-08-12T04:52:30Z
4个解决方案
46 votes

这是您的两阶段查找。

Base<T>::NO_ZEROFILL(除大写字母BTW外,所有大写字母标识符均为boo)是取决于this->NO_ZEROFILL的标识符。
由于当编译器首次解析模板时,尚无实际类型替代NO_ZEROFILL,因此编译器无法“知道” T是什么。 因此,它无法知道您假定要在其中定义的任何标识符(某些3007655734604608921604s可能会有专门化的含义,编译器稍后会看到),并且您无法从基类中定义的标识符中忽略基类限定条件。

这就是为什么您必须写Base<T>::NO_ZEROFILL(或this->NO_ZEROFILL)的原因。 这告诉编译器NO_ZEROFILL是基类中的内容,它取决于T,并且只能在实例化模板时稍后进行验证。 因此,它将接受它而不尝试验证代码。
当通过提供3007655734608928921604的实际参数实例化模板时,只能稍后验证该代码。

sbi answered 2020-08-12T04:52:55Z
29 votes

您遇到的问题是由于相关基类的名称查找规则所致。 14.6 / 8具有:

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

(这并不是真正的“两阶段查找”-有关此内容的说明,请参见下文。)

关于14.6 / 8的一点是,就编译器而言,在您的示例中bar是标识符,并且不依赖于模板参数。 因此,按照3.4.1和3.4.2中的常规规则进行查找。

此常规查询不会在bar内部进行搜索,因此NO_ZEROFILL只是一个未声明的标识符。 14.6.2 / 3具有:

在类模板或类模板的成员的定义中,如果类模板的基类 取决于模板参数,在不限定名称查找期间不检查基类范围 在类模板或成员的定义时或在类模板的实例化期间 或成员。

本质上,当您将barvoid NS::bar(A const &)进行限定时,您会将其从一个非依赖名称更改为一个依赖名称,并且在这样做时,将延迟其查找,直到实例化该模板。

旁注:什么是两阶段查找:

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

上面的示例编译如下。 编译器解析bar的函数主体,然后看到对具有依赖参数(即,依赖于模板参数的参数)的void NS::bar(A const &)的调用。 此时,编译器按照3.4.1进行查找,这就是“阶段1查找”。 查找将找到函数void bar (int),该函数与从属调用一起存储,直到以后。

然后实例化模板时(作为bar的调用的结果),编译器然后在参数范围内执行附加查找,这就是“阶段2查找”。 这种情况导致找到void NS::bar(A const &)

编译器对bar有两个重载,并在它们之间进行选择,在上述情况下,调用void NS::bar(A const &)

Richard Corden answered 2020-08-12T04:54:02Z
1 votes

似乎在vs 2008中可以编译。您是否尝试过:

public:
    Derived( bool initZero = Base<T>::NO_ZEROFILL );
Alan answered 2020-08-12T04:54:23Z
0 votes

试试这个程序

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

在3007657878787457458048行中,您还可以使用范围解析(::)运算符。 例如,尝试用

T get(void){return base<T>::x+2;}
shahnoor rahman answered 2020-08-12T04:54:48Z
translate from https://stackoverflow.com:/questions/1239908/why-doesnt-a-derived-template-class-have-access-to-a-base-template-class-ident