Последнее обновление:2026-10-12
Анализ исходников STL typename¶
В исходниках STL вниз встречаются такие строки — typedef в сочетании с typename; они выглядят очень сложными. Что же они значат? Давайте сегодня разберём это вместе!
template<typename _Iterator>
struct iterator_traits
{
typedef typename _Iterator::iterator_category iterator_category;
typedef typename _Iterator::value_type value_type;
typedef typename _Iterator::difference_type difference_type;
typedef typename _Iterator::pointer pointer;
typedef typename _Iterator::reference reference;
};
Распространённые способы использования typename¶
Сначала изучим типичные способы использования typename:
Выше — просто учебный пример; для полноценного сравнения пришлось бы учесть и специализированные версии. Возможно, вы заметили, что typename в приведённом коде можно заменить на class — и всё будет работать. Верно! Тогда возникает вопрос: есть ли разница между этими двумя способами? Если заглянуть в C++ Primer, выяснится, что они совершенно одинаковы.
Область видимости класса¶
При обращении извне класса к именам внутри класса можно использовать оператор области видимости класса. Вызовы вида MyClass::name обычно бывают трёх видов: статические данные-члены, статические функции-члены и вложенные типы:
struct MyClass {
static int A; //静态成员
static int B(){cout<<"B()"<<endl; return 100;} //静态函数
typedef int C; //嵌套类型
struct A1 { //嵌套类型
static int s;
};
};
При вызове можно писать напрямую:
Попробуем полный пример¶
Вернёмся к примеру с typename:
Какова цель этого кода? Первая реакция большинства: автор хотел определить указатель iter, указывающий на тип iterator, находящийся в области видимости класса T. Возможна такая структура, содержащая тип iterator:
Вызов такой:
Теперь строка с iter совершенно очевидна: это указатель типа MyIterator::iterator. Мы предполагаем, что дело обстоит так, — а так ли это на самом деле?
Но что если это нечто вроде T::iterator? T — параметр типа в шаблоне, и какой это будет тип, станет известно лишь при инстанцировании шаблона, не говоря уже о внутреннем iterator. Из приведённого выше рассказа об области видимости класса мы знаем, что T::iterator на деле может быть любым из трёх вариантов:
- статический данные-член
- статическая функция-член
- вложенный тип
В предыдущем примере ContainsAType::iterator — вложенный тип, и здесь всё в порядке. А если это статические данные-член? Что если тип, которым инстанцируется шаблонная функция foo, выглядит так:
Тогда T::iterator * iter; компилятор инстанцирует как MyIterator::iterator * iter; — а это что? Слева статическая переменная-член, а не тип, и выражение превращается в умножение; правда, iter здесь не определён, и компилятор выдаст ошибку:
typename¶
Имя, используемое в определении шаблона и зависящее от параметра шаблона, компилятор будет считать типом, только если такой тип существует среди параметров инстанцирования или если перед именем стоит модификатор — ключевое слово typename. Кроме этих двух случаев имя ни в коем случае не будет считаться типом.
Поэтому, если вы хотите прямо сообщить компилятору, что T::iterator — это тип, а не переменная, достаточно добавить typename:
Теперь компилятор может определить, что T::iterator — тип, уже не дожидаясь момента инстанцирования; тем самым устраняется упомянутая выше неоднозначность.
Разбор исходников¶
Вернёмся к исходникам STL
template<typename _Iterator>
struct iterator_traits
{
typedef typename _Iterator::iterator_category iterator_category;
typedef typename _Iterator::value_type value_type;
typedef typename _Iterator::difference_type difference_type;
typedef typename _Iterator::pointer pointer;
typedef typename _Iterator::reference reference;
};
Увидев это, мы сразу всё понимаем: здесь попросту с помощью typename сообщается, что _Iterator::iterator_category — тип, а затем typedef даёт ему новое имя; остальное аналогично!
Похожие темы¶
- Анализ исходников STL array | C++那些事
- Глубокий анализ STL string | C++那些事
- Разбор вопросов собеседования про STL string | C++那些事
- Анализ исходников STL deque | C++那些事
- Оптимизация пустого базового класса EBO в STL | C++那些事
- Реализация хеш-таблицы своими руками | C++那些事
- Хеш-таблица STL hashtable | C++那些事
- Анализ исходников STL итераторов | C++那些事
- Анализ исходников STL list | C++那些事
- STL map и multimap | C++那些事