Подтвердить что ты не робот

Использование ключевого слова typename с параметрами функции шаблона

В С++ требуется ключевое слово typename, чтобы компилятор мог устранить неоднозначность между вложенными типами и вложенными значениями в шаблонах. Однако существуют определенные ситуации, когда двусмысленность невозможна, например, когда производный класс наследуется от вложенного типа класса.

template <class T>
class Derived : public T::type
{ };

Здесь ключевое слово typename не требуется и на самом деле даже не разрешено. Это имеет смысл, потому что контекст устраняет двусмысленность. Здесь T::type должен ссылаться на тип, поскольку вы, очевидно, не можете наследовать от значения.

Я бы подумал, что то же самое верно для параметров шаблона функции.

template <class T>
void foo(const T::type& v)
{

}

В этом случае контекст дает понять, что T::type должен ссылаться на тип, поскольку параметр функции не может быть значением. Тем не менее, компилятор этого не принимает. Он хочет const typename T::type&. Это кажется непоследовательным. Почему язык допускает неявное предположение о вложенном типе в контексте наследования, но не в контексте параметров функции? В обоих случаях не может быть двусмысленности, поэтому зачем нужна typename в одном, а не другом?

4b9b3361

Ответ 1

Если вы слегка измените свое выражение, вы получите совершенно другую историю

template <class T>
void foo(T::type& v);

Это уже не однозначно. Он может объявить переменную типа void, которая инициализируется битовым выражением AND. Вся декларация будет задумана. Конечно, это семантически все глупости, но синтаксически это хорошо.

Синтаксически появление одного синтаксиса const делает его однозначным, но слишком много контекстной зависимости, чтобы сделать эту работу в компиляторе. Он должен помнить, что он читал const или любую другую такую ​​вещь, и когда он анализирует T::type после того, как ему нужно будет запомнить это имя как тип. Это также еще больше раздуло бы уже сложный Стандарт без веры.

Снова измените объявление функции

template <class T>
void foo(const T::type);

Даже внешний вид const в нем не обеспечивает однозначного разбора. Должно ли это объявление функции с неназванным параметром или должно быть объявлением функции с недопустимым именем параметра, которое пропускает его тип? Имя параметра анализируется с помощью declarator-id, который также может быть квалифицированным именем. Итак, здесь const будет принадлежать спецификаторам типа, а T::type будет проанализирован компилятором как имя параметра, в отсутствие typename. Это тоже полная бессмыслица, но синтаксически действительна.

В случае имен имен базового класса сам поиск имен утверждает, что имена не-типа игнорируются. Таким образом, вы получаете бездействие typename бесплатно: имя, которое имя поиска возвращает к более высокоуровневым модулям компилятора, либо относится к типу, либо поиск имени дал бы ошибку.

Я написал запись в FAQ о Где поставить "шаблон" и "typename" на зависимые имена.

Ответ 2

Во-первых, я не думаю, что когда-либо было намерение сделать резкое и точное различие между ситуациями, в которых допускаются только имена типов (например, имя базового класса) и ситуации, в которых допускаются непиковые сущности (например, выражения). Я бы сказал, что контекст имени базового класса был выделен по другой причине.

Во-вторых, не совсем правильно сказать, что в объявлениях параметров функции каждая сущность обязательно является typename. Вы можете объявить параметр следующим образом

template <class T>
void foo(const T::type& v[T::value]);

Конечно, грамматика в этом случае явно указывает, что type должно быть typename и value должно быть значением. Однако компилятор может понять это только после синтаксического анализа объявления, в то время как я полагаю, что идея typename была введена, чтобы помочь компилятору фактически начать правильный синтаксический анализ кода, то есть различие должно быть доступно до синтаксический анализ, как ввод в синтаксический анализ. Это различие может иметь глубокое влияние на интерпретацию кода.

Ответ 3

Было бы интересно найти, что вызывает это.

Я пытаюсь прочитать стандарт в поисках ответа, обратите внимание, что я новичок в этом.

Однако я считаю, что нашел соответствующее предложение.

§14.6.2. Имя, используемое в шаблоне декларации или определения и в зависимости от шаблона-параметра предполагается, что не следует указывать тип , если только поиск подходящего имени находит тип имя или имя ключевое слово typename.

Я предполагаю, что это означает, что проблема заключается в различии того, как работает поиск имени для списков спецификаторов базы данных и аргументов функции.

Поиск имени базового спецификатора:

§ 10.2. Во время поиска базы имя класса, имена не-типа игнорируются(3.3.10).

Это объясняет, почему typename не требуется для базовых спецификаций.

Ищете поиск имени аргумента функции.

Пожалуйста, исправьте меня, если это неправильное или несущественное предположение. Тем временем я продолжаю копать.

Ошибка, заданная VS2010, когда не квалифицируется аргумент шаблона в объявлении функции, выглядит следующим образом:

'T:: type': зависимое имя не является введите префикс типа 'typename' укажите тип.

Тем не менее, я все еще не понимаю правила поиска зависимого имени аргумента функции...