CodeRoadMap
路线图学习路径文章题库资源社区

浏览

首页路线图学习路径知识库题库文章资源社区我的学习
CodeRoadMap

中文编程学习导航:路线图、讲义与题库,进度可同步。

路线图学习路径文章题库社区

© 2026 CodeRoadMap

津ICP备2026012044号-1|coderoadmap@126.com
首页/C++ 那些事/typename

课程目录

  1. 01const 那些事
  2. 02static 那些事
  3. 03this 那些事
  4. 04inline 那些事
  5. 05sizeof 那些事
  6. 06纯虚函数和抽象类那些事
  7. 07vptr_vtable 那些事
  8. 08virtual 那些事
  9. 09volatile 那些事
  10. 10assert 那些事
  11. 11位域那些事
  12. 12extern 那些事
  13. 13struct 那些事
  14. 14struct 与 class 那些事
  15. 15union 那些事
  16. 16用 C 实现 C++ 多态
  17. 17explicit 那些事
  18. 18friend 那些事
  19. 19using 那些事
  20. 20:: 那些事
  21. 21enum 那些事
  22. 22decltype 那些事
  23. 23引用与指针那些事
  24. 24宏那些事
  25. 25C++11 新特性
  26. 26C++ STL源码剖析 tr1与std array
  27. 27C++ STL源码剖析之序列式容器deque
  28. 28C++ STL源码剖析之哈希表
  29. 29C++ STL源码剖析之实现一个简单的iterator_category
  30. 30C++ STL源码剖析之双向环形链表list
  31. 31C++ STL源码剖析之map、multimap、initializer_list
  32. 32从0到1打牢算法基础之手写一个哈希表
  33. 33C++ STL源码剖析之容器配接器stack与queue、priority_queue
  34. 34C++ STL源码剖析之红黑树
  35. 35STL之set与multiset那些事
  36. 36C++ STL 源码剖析之 Traits 编程技法
  37. 37typename
  38. 38C++ STL源码剖析之unordered_map、unordered_multimap、unordered_set、unordered_multiset
  39. 39STL源码剖析之vector
  40. 40STL设计之EBO(空基类优化)
  41. 41设计模式:单例模式
  42. 42初始化列表与赋值
  43. 43C++惯用法之enum class
  44. 44C++惯用法之消除垃圾收集器-资源获取即初始化方法(RAII)
  45. 45copy-swap 惯用法
  46. 46C++惯用法之pImpl
  47. 4710日c++实战狂练
  48. 48Day4 · const 练习
  49. 49��Ԫ���
  50. 50Day5 · 构造与析构
  51. 51Day5 · 继承与访问控制
  52. 52Day5 · 运算符重载
  53. 53Day5 · 三五法则
  54. 54Day5 · virtual 练习
  55. 55Day6 · 综合练习
  56. 56Day7 · 综合练习
  57. 57Day8 · 综合练习
  58. 58异常处理
  59. 59Day10 · 综合练习
  60. 60重点实战练习
第 37 课1.5 小时

typename

STL底层源码有下面几行,typedef与typename联用,这几个看着好复杂,究竟啥意思,我们今天一起来剖析!

课程内容

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的常见用法:

template <typename T>
int compare(const T &a, const T &b)
{
    return a>b?a:b;
}

上述只是个案例程序,如果想写的比较完整比较大小,还得考虑特化版本,也许你会想到上面这段代码中的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;
    };
};

调用的时候,可以直接调:

cout<<MyClass::A<<endl;
cout<<MyClass::B()<<endl;
MyClass:C c;
...

完整例子尝试

让我们回到一个typename的例子:

template <class T>
void foo() {
    T::iterator * iter;
    // ...
}

这段代码的目的是什么?多数人第一反应可能是:作者想定义一个指针iter,它指向的类型是包含在类作用域T中的iterator。可能存在这样一个包含类型的结构:

iterator
struct MyIterator {
    struct iterator {

    };
};

调用如下:

foo<MyIterator>();

这样一来,iter那行代码就很明显了,它是一个MyIterator::iterator类型的指针。我们猜测是这样的,现实是不是呢?

可是,如果是像T::iterator这样呢?T是模板中的类型参数,它只有等到模板实例化时才会知道是哪种类型,更不用说内部的iterator。通过前面类作用域的介绍,我们可以知道,T::iterator实际上可以是以下三种中的任何一种类型:

  • 静态数据成员
  • 静态成员函数
  • 嵌套类型

前面例子中的ContainsAType::iterator是嵌套类型,完全没有问题。可如果是静态数据成员呢?如果实例化foo模板函数的类型是像这样的:

struct MyIterator {
    static int iterator;
};

那么,T::iterator * iter;被编译器实例化为MyIterator::iterator * iter;,这是什么?前面是一个静态成员变量而不是类型,那么这便成了一个乘法表达式,只不过iter在这里没有定义,编译器会报错:

error: no type named ‘iterator’ in ‘struct MyIterator’

typename

对于用于模板定义的依赖于模板参数的名称,只有在实例化的参数中存在这个类型名,或者这个名称前使用了typename关键字来修饰,编译器才会将该名称当成是类型。除了以上这两种情况,绝不会被当成是类型。

因此,如果你想直接告诉编译器T::iterator是类型而不是变量,只需用typename修饰:

template <class T>
void foo() {
    typename T::iterator * iter;
}

这样编译器就可以确定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重命名一下,其余类似!

← 上一课C++ STL 源码剖析之 Traits 编程技法下一课 →C++ STL源码剖析之unordered_map、unordered_multimap、unordered_set、unordered_multiset