目录
1. 说明
在模板(包括别名模板)的声明或定义中,非当前实例的成员且依赖于模板参数的名称不视为类型,除非使用关键字 typename 或除非它已被建立为类型名称(例如使用 typedef 声明或用于命名基类)。
2. 示例
#include <iostream>
#include <vector>
int p = 1;
template<typename T>
void foo(const std::vector<T>& v)
{
// std::vector<T>::const_iterator 是一个依赖名,
typename std::vector<T>::const_iterator it = v.begin();
// 如果没有“typename”, 以下被解析为类型相关数据成员“const_iterator”和某个变量“p”// 的乘法。因为在这一点有一个全局的可见 “p” ,此基板定义会编译
std::vector<T>::const_iterator* p; //认为 p 是上面的 int p
//typename std::vector<T>::const_iterator* p; //如此则认为 p 是//std::vector<T>::const_iterator指针类型
typedef typename std::vector<T>::const_iterator iter_t;
iter_t* p2; // “iter_t” 是一个依赖名, 但它被认为是一个类型名称(而不是变量)
}
template<typename T>
struct S
{
typedef int value_t; // 当前实例成员
void f()
{
S<T>::value_t n{}; // S<T> 是依赖的, 但无需“typename”
std::cout << n << '\n';
}
};
int main()
{
std::vector<int> v;
foo(v); // 模板实例化失败: 没有成员变量
//按类型 std::vector<int>调用“const_iterator”
S<int>().f();
}
关键字 typename 只能以这种方式在限定名称(例如 T::x)之前使用,但名称不需要依赖。通常使用限定名称查找来查找以 typename 为前缀的标识符。与使用详细类型说明符的情况不同,查找规则不会因限定符而改变:
struct A // A 嵌入变量 X 和一个嵌入类型 struct X
{
struct X {};
int X;
};
struct B
{
struct X {}; // B 有一个嵌入类型 struct X
};
template<class T>
void f(T t)
{
typename T::X x;
}
void foo()
{
A a;
B b;
f(b); // OK: 实例化 f<B>, T::X 指的是 B::X
f(a); // error: 不能实例化 f<A>:
// 因为修饰名查找 A::X 时找到数据成员
}
关键字 typename 甚至可以在模板之外使用。
#include <vector>
int main()
{
typedef typename std::vector<int>::const_iterator iter_t;
typename std::vector<int> v;
}
再比如标准库中 std::condiitonal 中的定义:
template <bool _Test, class _Ty1, class _Ty2>
struct conditional { // Choose _Ty1 if _Test is true, and _Ty2 otherwise
using type = _Ty1;
};
template <bool _Test, class _Ty1, class _Ty2>
using conditional_t = typename conditional<_Test, _Ty1, _Ty2>::type; //如果去掉 typename ,
//则会提示语法错误: 标识符“type”