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

URI:: Escape делает то, что Вы хотите.

use URI::Escape;

sub escape_hash {
    my %hash = @_;
    my @pairs;
    for my $key (keys %hash) {
        push @pairs, join "=", map { uri_escape($_) } $key, $hash{$key};
    }
    return join "&", @pairs;
}

43
задан Sorangwala Abbasali 29 August 2016 в 10:29
поделиться

3 ответа

Это двухэтапный поиск.

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

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

46
ответ дан 26 November 2019 в 22:54
поделиться

Проблема, с которой вы столкнулись, связана с правилами поиска имен для зависимых базовых классов. 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 имеет:

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

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

Примечание: что такое двухэтапный поиск:

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 &) .

29
ответ дан 26 November 2019 в 22:54
поделиться

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

public:
    Derived( bool initZero = Base<T>::NO_ZEROFILL );
1
ответ дан 26 November 2019 в 22:54
поделиться
Другие вопросы по тегам:

Похожие вопросы: