Использование ключевого слова 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' в укажите тип.
тем не менее, я все еще неясно о правилах поиска имени аргумента зависимой функции...