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


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

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

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

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

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

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

3 ответа:

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

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 <class T>
void foo(const T::type& v[T::value]);
Конечно, грамматика в этом случае явно диктует, что type должно быть именем типа, а value - значением. Однако компилятор может понять это только послесинтаксического анализа объявления, в то время как я считаю, что идея typename была введена, чтобы помочь компилятору фактически начать правильный синтаксический анализ кода, т. е. различие должно быть доступно до синтаксического анализа, как вход в код. синтаксический анализ. Это различие может иметь глубокие последствия для толкования кодекса.

Было бы интересно узнать, что является причиной этого.

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

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

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

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

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

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

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

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

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

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

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

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