Использование ключевого слова typename с параметрами функции шаблона - PullRequest
28 голосов
/ 03 декабря 2010

В C ++ необходимо ключевое слово 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 в одном, а не в другом?

Ответы [ 3 ]

23 голосов
/ 03 декабря 2010

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

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

Я написал в разделе часто задаваемых вопросов о Где поставить "template" и "typename" на зависимые имена .

4 голосов
/ 03 декабря 2010

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

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

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

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

2 голосов
/ 03 декабря 2010

Было бы интересно найти причину этого.

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

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

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

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

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

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

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

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

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

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

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

Однако мне все еще неясно, какие правила для поиска имен аргументов зависимых функций ...

...