Использование ключевого слова 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 ответа:
Если вы немного измените свою декларацию, вы получите совершенно другую историю
Это уже не является однозначным. Он может объявить переменную типа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' в укажите тип.
Однако мне все еще неясны правила поиска имени аргумента зависимой функции...