typename
В определениях шаблонов typename предоставляется указание компилятору о том, что неизвестный идентификатор является типом. В списках параметров шаблона используется для указания параметра типа.
Синтаксис
typename identifier ;
Замечания
typename Ключевое слово необходимо использовать, если имя в определении шаблона — это полное имя, зависящее от аргумента шаблона; необязательно, если полное имя не зависит. Дополнительные сведения см. в разделе «Шаблоны» и «Разрешение имен».
typename может использоваться любым типом в любом месте объявления или определения шаблона. Он не допускается в списке базовых классов, если только не в качестве аргумента шаблона в базовый класс шаблона.
template class C1 : typename T::InnerType // Error - typename not allowed. <>; template class C2 : A // typename OK. <>;
Ключевое слово typename также можно использовать вместо class списков параметров шаблона. Например, следующие операторы семантически эквивалентны:
template. template.
Пример
// typename.cpp template class X < typename T::Y m_y; // treat Y as a type >; int main()
Что значит typename?
typedef я знаю.
typename — не уверен что понимаю это ключевое слово. Вне template как я понял используется для помощи компилятору в определении типа.
а что происходит дальше std::stack::container_type::iterator ? разве у стека есть итератор?
- Вопрос задан более двух лет назад
- 572 просмотра
Комментировать
Решения вопроса 1
Станислав Макаров @Nipheris Куратор тега C++
1. typename в данном случае нужен компилятору только как подсказка от разработчика, что последующий идентификатор (т.е. std::stack
2. Member-тип container_type эквивалентен типу нижележащего контейнера (т.к. std::stack — это адаптер под интерфейс стека, а не реальный контейнер, реальный контейнер для хранения вы выбираете вторым параметром шаблона, по-умолчанию это std::deque).
3. Вот у std::deque итератор действительно есть.
Зачем надо писать typename для уточнения типа?
@fori1ton: там не аналогичный пример. Насколько я понял, ОП спрашивает зачем в этом коде сделан typename.
25 июл 2013 в 13:16
Подробное описание находится по ссылке представленной @fori1ton. Если кратко, то компилятор не знает, что означает const_iterator . Синтаксис схож как для переменной, так и для объявления типов ( typedef ). Оператор typename говорит, что это имя типа (не переменная).
25 июл 2013 в 13:17
@Expert: а что может означать строка T::const_iterator pos кроме как не объявление типа? Не T::const_iterator * pos , а именно T::const_iterator pos ? Компилятор не знает что именно такое T::const_iterator, но что здесь можно предположить как не тип? Помоему в этом вопрос заключается. Сам я склоняюсь к тому, что это, если не ошибаюсь, требование стандарта.
25 июл 2013 в 13:25
@fori1ton, читал ещё давно, но тут же нету звездочки как подметил @fogbit. То есть компилятор не может определить какой тип туда попадет и это делается в рантайм? Но даже если и так, то без typename выйдет же T(тип)::const_iterator(имя переменной) pos(имя переменной), но такое объявление вызовет ошибку. Если есть строчка в стандарте, в которой сказано о необходимости typename в такой ситуации, то зачем она нужна? Ведь компилятор именно в этом случае может и сам справится.
25 июл 2013 в 14:08
@Robert Pinkman: непосредственно тип выводится в момент инстанса шаблона в коде, т.е. в compile-time. C шаблонами вообще всё происходит в compile-time, если не ошибаюсь. Подозреваю что Стандарт не делает различий в ситуациях, а просто декларирует что если есть объявление типа, зависящего от шаблона в любом контексте, то пиши перед ним typename .
25 июл 2013 в 14:45
1 ответ 1
Сортировка: Сброс на вариант по умолчанию
Проблема в том, что T::const_iterator — зависимое имя: оно зависит от параметра шаблона T . В этой точке компилятор не знает, каким будет T , и не может предсказать, будет ли T::const_iterator именем типа или, например, именем статического поля или вообще шаблона. Поэтому он и не пытается угадать, и предполагает, что это поле.
Если же ему подсказать, он будет предполагать, что T::const_iterator — это тип, и поймёт, что
typename T::const_iterator pos;
Почему же компилятор не может подождать с выяснением смысла выражения T::const_iterator до того момента, когда тип T будет уже известен (то есть, до момента разворачивания шаблона с конкретным типом T )? А вот почему: на момент применения шаблона тип T имеет право быть ещё не определён! И ещё он может зависеть от самого шаблона. Так что откладывать выяснение смысла выражения нельзя. Пример:
template class comparable < bool compare(T& other) < return this == other; >>; class length : public comparable // в этой точке для comparable // тип T ещё не известен полностью! < .
Пример кода, иллюстрирующего «скользкие» моменты, приведён ниже. Он не компилируется gcc (так как нету полагающегося по стандарту typename ), но более либеральный MSVC 2012 его компилирует и выполняет.
typename для того и нужен, чтобы исключить подобные сюрпризы.
#include "stdafx.h" // нужно для MSVC #include using namespace std; template struct A < void f() < // если T::iterator - тип, это предварительное объявление функции // если T::iterator - число, это объявление переменной с инициализацией int x(T::iterator); >void g() < int x = 5; < // если T::iterator - шаблон, принимающий числовой аргумент, // это инстанциация шаблона в переменную x, перекрывающую x // за фигурными скобками // если T::iterator -- экземпляр класса с перегруженным оператором x; // Кто-то всё ещё сомневается, что C++ - непредсказуемый язык? > > >; struct T1 < typedef int iterator; >; struct T2 < static const int iterator = 5; >; struct T3 < templatestruct iterator < iterator() < cout >; >; struct T4 < struct Titerator < Titerator operator < (int value) < cout bool operator > (int value) < cout " >; static Titerator iterator; >; T4::Titerator T4::iterator = T4::Titerator(); int main(int argc, char* argv[]) < Aa1; a1.f(); A a2; a2.f(); A a3; a3.g(); A a4; a4.g(); return 0; >
Результат работы таков:
constructing template with C = 0
in operator < 0
in operator > 5
Typename c что это
Во всех примерах шаблонов у Страуструпа пишется:
template class T> …
Но кроме этого есть еще ключевое слово typename, и можно написать так:
template typename T> …
template struct T>…
или не дай бог так
template union T>…
Ну и так далее. Как правильно делать и зачем нужен typename?
Re: Зачем нужен typename?
От: | Lorenzo_LAMAS |
Дата: | 26.04.05 10:59 |
Оценка: |
Здравствуйте, Ignoramus, Вы писали:
I>Во всех примерах шаблонов у Страуструпа пишется:
I>
template class T> …
Да, как он сам резонно замечает, он использует такой стиль ради краткости.
I>Но кроме этого есть еще ключевое слово typename, и можно написать так:
I>
template typename T> …
Да, можно и так. А вот например, как в книге Гуртового и Абрамса они мотивируют то, что они используют (для примеров в книге class) — чтобы в таком случае templateи т.д. объявление параметра не-типа явно отличалось от параметра — типа.
I>а еще так?
I>
template struct T>…
Так нельзя. Хотя Стен Липман в "Inside C++ object model" говорит, что ради шутки он в своем cfront'е такое добавлял.
I>или не дай бог так
I>
template union T>…
Так нельзя.
I>Ну и так далее. Как правильно делать и зачем нужен typename?
Делать можно как угодно, ибо в данном случае typename и class — равнозначны. Но вот, например, при объявление шаблона параметра шаблона можно использовать уже только class — templateclass A>.
А еще есть и другое использование typename, для указанию компилятору, что зависимое имя — имя типа, но об этом ты уж либо у Бьярна почитай, либо в форуме поищи — было здесь мнооого раз.
Of course, the code must be complete enough to compile and link.
Re: Зачем нужен typename?
От: | jazzer | Skype: enerjazzer |
Дата: | 26.04.05 11:00 | |
Оценка: |