Проблема, с которой вы столкнулись, связана с правилами поиска имен для зависимых базовых классов. 14,6 / 8 имеет:
При поиске объявления имени, используемого в определении шаблона, применяются обычные правила поиска (3.4.1,
3.4.2) используются для независимых имен. Поиск имен в зависимости от параметров шаблона
откладывается до тех пор, пока фактический аргумент шаблона не станет известен (14.6.2).
(Это на самом деле не «двухфазный поиск» - объяснение этого см. Ниже).
Смысл 14.6 / 8 в том, что компилятор NO_ZEROFILL
в вашем примере является идентификатором и не зависит от параметра шаблона. Поэтому он рассматривается в соответствии с обычными правилами в 3.4.1 и 3.4.2.
Этот обычный поиск не ищет внутри Base<T>
, поэтому NO_ZEROFILL - это просто необъявленный идентификатор. 14.6.2 / 3 имеет:
В определении шаблона класса или члена шаблона класса, если базовый класс шаблона класса
зависит от шаблона-параметра, область видимости базового класса не проверяется во время поиска по неквалифицированному имени
либо в точке определения шаблона класса или члена, либо во время создания шаблона класса
или член.
Когда вы квалифицируетесь NO_ZEROFILL
с Base<T>::
по сути, вы меняете его с не зависимого имени на зависимое, и когда вы делаете это, вы задерживаете его поиск до создания экземпляра шаблона.
Примечание: Что такое двухфазный поиск:
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 &)
.