Почему class производных шаблонов не имеет доступа к идентификаторам базового шаблона?

Рассматривать:

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

Я не могу скомпилировать это с GCC g ++ 3.4.4 (cygwin).

До их преобразования в шаблоны classов они были неэквивалентными, и производный class смог увидеть статические элементы базового classа. Является ли эта потеря видимости требованием спецификации C ++ или есть синтаксическое изменение, которое мне нужно использовать?

Я понимаю, что каждый экземпляр Base будет иметь свой собственный статический член « ZEROFILL » и « NO_ZEROFILL », что Base::ZEROFILL и Base::ZEROFILL – это разные переменные, но я не очень забота; постоянная есть для удобочитаемости кода. Я хотел использовать статическую константу, потому что это более безопасно с точки зрения конфликтов имен, а не макросов или глобальных.

Это двухфазный поиск для вас.

Base::NO_ZEROFILL (все идентификаторы колпачков являются boo, кроме макросов, BTW) – это идентификатор, который зависит от T
Так как, когда компилятор сначала анализирует шаблон, нет никакого действительного типа, замененного для T , компилятор не «знает», что такое Base . Таким образом, он не может знать никаких идентификаторов, которые вы предполагаете определенными в нем (может быть специализация для некоторых T s, которые компилятор видит только позже), и вы не можете опустить квалификацию базового classа из идентификаторов, определенных в базовом classе.

Вот почему вам нужно написать Base::NO_ZEROFILL (или this->NO_ZEROFILL ). Это говорит компилятору, что NO_ZEROFILL – это что-то в базовом classе, которое зависит от T , и что оно может проверять только позже, когда экземпляр шаблона создается. Поэтому он примет его, не пытаясь проверить код.
Этот код может быть проверен позже, когда шаблон создается путем подачи фактического параметра для T

Проблема, с которой вы столкнулись, связана с правилами поиска имен для зависимых базовых classов. 14.6 / 8 имеет:

При поиске декларации имени, используемого в определении шаблона, обычные правила поиска (3.4.1, 3.4.2) используются для независимых имен. Поиск имен, зависящих от параметров шаблона, откладывается до тех пор, пока не будет известен фактический аргумент шаблона (14.6.2).

(На самом деле это не «двухфазный поиск» – см. Ниже объяснение этого.)

Точка около 14.6 / 8 заключается в том, что в отношении компилятора NO_ZEROFILL в вашем примере является идентификатором и не зависит от параметра шаблона. Поэтому он рассматривается в соответствии с обычными правилами в разделах 3.4.1 и 3.4.2.

Этот нормальный поиск не выполняет поиск внутри Base и поэтому NO_ZEROFILL – это просто необъявленный идентификатор. 14.6.2 / 3:

В определении шаблона classа или члена шаблона classа, если базовый class шаблона classа зависит от параметра шаблона, область базового classа не рассматривается при поиске неквалифицированного имени либо в точке определения classа шаблона или члена или во время создания шаблона или члена classа.

Когда вы квалифицируете NO_ZEROFILL с Base:: по существу, вы меняете его на не зависимое имя на зависимое, и когда вы это делаете, вы задерживаете его поиск до тех пор, пока не будет создан экземпляр шаблона.

Боковое примечание: что такое двухфазный поиск:

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

Вышеприведенный пример компилируется следующим образом. Компилятор анализирует тело функции foo и видит, что есть вызов bar который имеет зависимый аргумент (т. Е. Тот, который зависит от параметра шаблона). В этот момент компилятор просматривает панель согласно 3.4.1, и это «поиск по фазе 1». Поиск найдет функцию void bar (int) и будет храниться с зависимым вызовом до более позднего времени.

Когда шаблон затем создается (в результате вызова из main ), компилятор затем выполняет дополнительный поиск в области аргумента, это «поиск фазы 2». Этот случай приводит к обнаружению void NS::bar(A const &) .

Компилятор имеет две перегрузки для bar и выбирает между ними, в приведенном выше случае вызывает void NS::bar(A const &) .

Кажется, компилировать ok в vs 2008. Вы пробовали:

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

Попробуйте эту программу

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

в строке T get(void){return this->x+2;} u также можно использовать оператор разрешающей способности (: :). например, попробуйте заменить строку на

 T get(void){return base::x+2;} 
  • Можно ли создавать стандартные шаблоны контейнеров с неполными типами?
  • Ошибка «Undefined symbols» с компоновщиком простого шаблона
  • Регистрация типа C ++ во время компиляции
  • Вызов функции для каждого вариационного аргумента шаблона и массива
  • Почему шаблон функции не может быть частично специализированным?
  • Почему шаблонный вывод не работает здесь?
  • Полученный доступ к шаблону classа к элементам-членам базового classа
  • Синглтоны: хороший дизайн или костыль?
  • В шаблоном производном classе, почему мне нужно квалифицировать имена членов базового classа с помощью «this->» внутри функции-члена?
  • Делают ли c ++ шаблоны медленными?
  • Специализация шаблона и проблемы с enable_if
  • Давайте будем гением компьютера.