Por que uma class de modelo derivada não tem access a identificadores de uma class de modelo base?

Considerar:

template  class Base { public: static const bool ZEROFILL = true; static const bool NO_ZEROFILL = false; } template  class Derived : public Base { public: Derived( bool initZero = NO_ZEROFILL ); // NO_ZEROFILL is not visible ~Derived(); } 

Eu não sou capaz de compilar isso com GCC g ++ 3.4.4 (cygwin).

Antes de convertê-los em modelos de classs, eles não eram genéricos e a class derivada era capaz de ver os membros estáticos da class base. Essa perda de visibilidade é um requisito da especificação C ++ ou há uma alteração de syntax que preciso empregar?

Eu entendo que cada instanciação de Base terá seu próprio membro estático ” ZEROFILL ” e ” NO_ZEROFILL “, que Base::ZEROFILL e Base::ZEROFILL são variables ​​diferentes, mas eu realmente não Cuidado; a constante está lá para a legibilidade do código. Eu queria usar uma constante estática porque isso é mais seguro em termos de conflitos de nome, em vez de uma macro ou global.

Essa é uma pesquisa de duas fases para você.

Base::NO_ZEROFILL (todos os identificadores maiúsculos são boo, exceto para macros, BTW) é um identificador que depende de T
Desde que, quando o compilador primeiro analisa o template, não existe nenhum tipo real substituído por T , o compilador não “sabe” o que é o Base . Portanto, ele não pode conhecer nenhum identificador que você assume estar definido nele (pode haver uma especialização para alguns Ts que o compilador vê apenas mais tarde) e você não pode omitir a qualificação da class base dos identificadores definidos na class base.

É por isso que você tem que escrever Base::NO_ZEROFILL (ou this->NO_ZEROFILL ). Isso diz ao compilador que NO_ZEROFILL é algo na class base, que depende de T , e que só pode verificá-lo mais tarde, quando o modelo é instanciado. Portanto, ele será aceito sem tentar verificar o código.
Esse código só pode ser verificado mais tarde, quando o modelo é instanciado fornecendo um parâmetro real para T

O problema que você encontrou é devido às regras de pesquisa de nomes para classs base dependentes. 14.6 / 8 tem:

Ao procurar a declaração de um nome usado em uma definição de modelo, as regras de pesquisa usuais (3.4.1, 3.4.2) são usadas para nomes não dependentes. A pesquisa de nomes dependentes dos parâmetros do modelo é adiada até que o argumento real do modelo seja conhecido (14.6.2).

(Isso não é realmente “pesquisa de 2 fases” – veja abaixo uma explicação sobre isso).

O ponto sobre 14.6 / 8 é que, no que diz respeito ao compilador, NO_ZEROFILL no seu exemplo é um identificador e não depende do parâmetro do modelo. Portanto, ele é considerado de acordo com as regras normais em 3.4.1 e 3.4.2.

Essa pesquisa normal não pesquisa dentro de Base e, portanto, NO_ZEROFILL é simplesmente um identificador não declarado. 14.6.2 / 3 possui:

Na definição de um modelo de class ou membro de um modelo de class, se uma class base do modelo de class depender de um parâmetro de modelo, o escopo da class base não será examinado durante a consulta de nome não qualificado no ponto de definição da class. modelo ou membro ou durante uma instanciação do modelo de class ou membro.

Quando você qualifica NO_ZEROFILL com Base:: em essência você está mudando de um nome não dependente para um dependente e quando você faz isso você atrasa sua pesquisa até que o modelo seja instanciado.

Nota lateral: O que é a pesquisa em duas fases:

 void bar (int); template  void foo (T const & t) { bar (t); } namespace NS { struct A {}; void bar (A const &); } int main () { NS::A a; foo (a); } 

O exemplo acima é compilado da seguinte maneira. O compilador analisa o corpo da function foo e vê que há uma chamada para bar que possui um argumento dependente (isto é, um que depende do parâmetro template). Neste ponto, o compilador procura a barra de acordo com 3.4.1 e esta é a “pesquisa da fase 1”. A pesquisa localizará a function void bar (int) e será armazenada com a chamada dependente até mais tarde.

Quando o modelo é instanciado (como resultado da chamada do main ), o compilador executa uma pesquisa adicional no escopo do argumento, essa é a “pesquisa da fase 2”. Este caso que resulta em encontrar void NS::bar(A const &) .

O compilador tem duas sobrecargas para a bar e seleciona entre elas, no caso acima chamando void NS::bar(A const &) .

Parece compilar ok em vs 2008. Você já tentou:

 public: Derived( bool initZero = Base::NO_ZEROFILL ); 

Experimente este programa

 #include using namespace std; template  class base{ public: T x; base(T a){x=a;} virtual T get(void){return x;} }; template  class derived:public base{ public: derived(T a):base(a){} T get(void){return this->x+2;} }; int main(void){ base ob1(10); cout< ob(10); cout< 

no T get(void){return this->x+2;} linha u também pode usar o operador de resolução de escopo (: :). por exemplo, tente replace a linha com

 T get(void){return base::x+2;}