typename


声明模板参数:template<typename T> ...,只有在这种语境下,typename关键字才可以和class关键字互换

  • class关键字 声明类:class A{...}; 声明模板参数:template<class T> ...
  • typename关键字 声明模板参数:template<typename T> ... 解决嵌套依赖:typename T::A a;
  • 无论是声明模板参数还是解决嵌套依赖,都不能使用struct关键字

解决嵌套依赖

  • 在第一次编译模板代码时,模板参数的具体类型尚不明确,编译器会把依赖于模板参数的嵌套类型理解为某个类的静态成员变量,因此当它看到代码中使用这样的标识符声明其它变量时,会报错误,这就叫嵌套依赖。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
class X
{
public:
    class A{}; // A 是X的嵌套类型
};
template<typename T> void foo()
{
    T::A a; // 错误
}
foo<A>();
  • typename关键字旨在告诉编译器,所引用的标识符是个类型名,可以声明变量,具体类型等到实例化时再定 template<typename T> void foo(){typename T::A a; ....}

template


依赖模板参数的模板成员访问

  • 在模板代码中,通过依赖于模板参数的对象,引用或指针,访问其带有模板特性的成员,编译器常常因为无法正确理解模板参数列表的左右尖括号,而报编译错误。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
class A
{
public:
    template<typename T> void foo(){...}
};
template<typename T> void foo(T& t, T* p)
{
    r.foo<int>(); // 错误
    p->foo<int>(); // 错误
}
A a;
foo(a, &a);
  • 在模板名前面加上template关键字,意在告诉编译器其后名称是一个模板,便与其就可以正确理解“<>”了。
1
2
3
4
5
template<typename T> void foo(T& t, T* p)
{
    t.template foo<int>();
    p->template foo<int>();
}

子模板访问基模板