Иногда я видел несколько действительно неразборчивых сообщений об ошибках, выплевывающих gcc
при использовании шаблонов ... В частности, у меня были проблемы, когда кажущиеся правильными объявления вызывали очень странные ошибки компиляции, которые волшебным образом исчезали, добавляя typename
ключевое слово в начале объявление ... (Например, буквально на прошлой неделе я объявлял два итератора как члены другого шаблонного класса, и мне пришлось это сделать) ...
Что за история typename
?
Ответы:
Ниже приводится цитата из книги Джозаттиса:
источник
typename
(хотя и не всех!).Сообщение Стэна Липпмана в блоге предлагает: -
Итак, в основном Страуструп повторно использовал ключевое слово класса без введения нового ключевого слова, которое впоследствии изменяется в стандарте по следующим причинам
В приведенном примере
грамматика языка неверно интерпретируется
T::A *aObj;
как арифметическое выражение, поэтому вводится новое ключевое слово, называемоеtypename
он инструктирует компилятор рассматривать последующий оператор как объявление.
Вот почему у нас есть оба
Вы можете взглянуть на этот пост , он определенно поможет вам, я просто извлек из него все, что мог
источник
typename
нужно новое ключевое слово , если можно было использовать существующее ключевое словоclass
для той же цели?typename
стало необходимо исправить проблему синтаксического анализа, как описано в ответе Naveen, цитируя Josuttis. (Я не думаю, что вставкаclass
в этом месте сработала бы.) Только после того, как новое ключевое слово было принято для этого случая, оно также было разрешено в объявлениях аргументов шаблона ( или это определения? ), Потому чтоclass
всегда было что-то вводит в заблуждение.Рассмотрим код
К сожалению, компилятор не обязан быть экстрасенсом и не знает, будет ли T :: sometype в конечном итоге ссылаться на имя типа или статический член T. Итак, можно
typename
сказать это:источник
В некоторых ситуациях, когда вы ссылаетесь на член так называемого зависимого типа (что означает «зависит от параметра шаблона»), компилятор не всегда может однозначно вывести семантическое значение результирующей конструкции, потому что он не знает, что это за имя (т.е. является ли это именем типа, именем элемента данных или именем чего-то еще). В подобных случаях вы должны устранить неоднозначность ситуации, явно указав компилятору, что имя принадлежит типу, определенному как член этого зависимого типа.
Например
В этом примере ключевое слово
typename
необходимо для компиляции кода.То же самое происходит, когда вы хотите сослаться на член шаблона зависимого типа, то есть на имя, обозначающее шаблон. Вы также должны помочь компилятору с помощью ключевого слова
template
, хотя оно размещено иначеВ некоторых случаях может потребоваться использовать оба
(если я правильно понял синтаксис).
Конечно, другая роль ключевого слова
typename
должна использоваться в объявлениях параметров шаблона.источник
Секрет заключается в том, что шаблон может быть специализирован для некоторых типов. Это означает, что он также может определять интерфейс совершенно по-разному для нескольких типов. Например, вы можете написать:
Можно спросить, почему это полезно и действительно: это действительно выглядит бесполезным. Но имейте в виду, что, например,
std::vector<bool>
этотreference
тип выглядит совершенно иначе, чем для другихT
s. По общему признанию, это не меняет видreference
от типа к чему-то другому, но, тем не менее, это может случиться.Что произойдет, если вы напишете свои собственные шаблоны, используя этот
test
шаблон. Что-то вроде этогокажется, вам это подходит, потому что вы ожидаете, что
test<T>::ptr
это тип. Но компилятор не знает, и на самом деле стандарт даже советует ему ожидать обратного,test<T>::ptr
это не тип. Чтобы сообщить компилятору, чего вы ожидаете, вам нужно добавить файлtypename
before. Правильный шаблон выглядит такИтог: вы должны добавлять
typename
раньше всякий раз, когда вы используете вложенный тип шаблона в своих шаблонах. (Конечно, только если параметр шаблона вашего шаблона используется для этого внутреннего шаблона.)источник
Два использования:
template
ключевого слова аргумента (вместоclass
)typename
Ключевое слово указывает компилятору , что идентификатор является типом (а не переменной - члена статический)источник
Я думаю, что во всех ответах упоминалось, что
typename
ключевое слово используется в двух разных случаях:а) При объявлении параметра типа шаблона. например
Которой между ними нет разницы и они ТОЧНО одинаковые.
б) Перед использованием имени вложенного зависимого типа для шаблона.
Который неиспользование
typename
приводит к ошибкам синтаксического анализа / компиляции.Что я хочу добавить ко второму случаю, как упоминалось в книге Скота Мейерса « Эффективный C ++» , так это то, что существует исключение использования
typename
перед именем вложенного зависимого типа . Исключением является то, что если вы используете имя вложенного зависимого типа либо как базовый класс, либо в списке инициализации членов , вы не должны использовать егоtypename
там:Примечание. Использование
typename
для второго случая (т.е. перед именем вложенного зависимого типа) не требуется, начиная с C ++ 20.источник
источник