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

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

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 ответов


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

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" на зависимые имена.


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

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

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

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


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

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

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

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

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

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

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

Это объясняет, почему typename не требуется для основания описатели.

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

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

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

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

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