2010-12-03 2 views
28

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

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

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

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

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

} 

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

+3

Это очень интересный вопрос. – 2010-12-03 16:42:42

+1

Члены комитета C++ являются людьми. Отправьте предлагаемое изменение для следующего стандарта. – 2010-12-03 16:58:15

+0

@ Channel72 во время моего короткого контакта с шаблонами Я понял, что существует еще много непоследовательных и неортогональных правил. Я не могу сказать, что шаблоны были плохо спроектированы, но для улучшения есть определенная комната (комната для гостей не какая-то небольшая комната). – 2010-12-03 17:02:51

ответ

22

Если немного изменить объявление, вы получите всю другую историю

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. Это тоже полная бессмыслица, but is syntactically valid.

В случае имен базового класса сам поиск имени гласит, что имена не-типа игнорируются. Таким образом, вы получаете упущение typename: имя, которое имя поиска возвращает к более высокоуровневым модулям компилятора, либо относится к типу, либо поиск имени дал бы ошибку.

Я написал запись в FAQ о Where to put the "template" and "typename" on dependent names.

2

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

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

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

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

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

Base имя спецификатор поиска:

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

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

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

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

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

«T :: типа»: зависимое имя не типа префикса с «TypeName» в укажите тип.

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

4

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

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

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

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

Смежные вопросы