template <typename T>
struct bar: public foo<T>
{
using foo<T>::foo<T>;
};
Чтобы этот синтаксический анализ выполнялся правильно, вам нужно вставить template
перед foo<T>;
, чтобы сообщить компилятору, что foo
следует рассматривать как имя шаблона (он не может смотреть на foo<T>
сказать себе, так как T
неизвестно).Но использование ::template
не разрешено в объявлении использования.Имя также не относится ко всем конструкторам bar
: Вместо этого оно будет ссылаться на конкретную специализацию шаблона функции конструктора (T
- аргумент шаблона) такого конструктора, как показано ниже
template<typename T>
foo();
Кроме того, в объявлении using недопустимо использовать template-id
(например, foo<T>
) в качестве имени (что фактически запрещает ему ссылаться на специализацию шаблона функции, с добавлением запрета на специализации шаблона функции преобразования имен, указанныйтоже), так что даже если вы исправите проблему синтаксического анализа, используя ::template
(если это будет возможно), вы все равно выдадите ошибку на этом этапе.
Когда были введены унаследованные конструкторы, были добавлены специальные правила, позволяющие ссылаться на конструктор с помощью синтаксического правила: если у вас есть квалифицированный идентификатор (который в основном является квалифицированным именем, использующим ...::...
), и последний квалифицированныйперед тем, как заключительная часть назовет конкретный класс, вы можете обозначить конструктор (ы) этого класса двумя дополнительными способами:
- Если класс был назван с использованием идентификатора шаблона (имяform
foo<T>
) и последняя часть соответствует имени шаблона (так, foo<T>::foo
или TTP<T>::TTP
с TTP
, являющимся параметром шаблона шаблона). - Если последняя часть соответствует имени класса (так,
foo::foo
или T::T
, где T
является параметром шаблона).
Эти два дополнительных правила активны только в объявлении использования.И они, естественно, не присутствовали в C ++ 03.Другое правило, которое также присутствовало в C ++ 03: если конечная часть называет имя внедренного класса, то это квалифицированное имя также ссылается на конструктор:
foo::foo
будет работать для него.Но с одним только этим правилом T::T
(где T
обозначает класс foo
) не будет работать, потому что foo
не имеет члена с именем T
.
Для этого при наличии специальных правил вы можете написать
using foo<T>::foo;
using bar::foo::foo; // valid too
Второе также верно: foo
- это имя внедренного класса, которое было введено в базовый класс.foo<T>
и наследуется до bar
.Мы ссылаемся на это имя как bar::foo
, а затем добавляем последнюю часть foo
, которая снова ссылается на введенное имя класса, чтобы обозначить конструктор (ы) `foo.
Теперь вы понимаете, почему исходное имя, которое вы пробовали, ссылается на специализацию шаблона функции конструктора (если это разрешено): потому что часть foo<T>::foo
будет называть все конструкторы, а <T>
, которыйпоследует, отфильтрует шаблон и передаст аргумент типа.