可能重复:正式,什么是typename?我必须在哪里以及为什么要放置模板和typename关键字?
考虑以下代码:
template<class K>
class C {
struct P {};
vector<P> vec;
void f();
};
template<class K> void C<K>::f() {
typename vector<P>::iterator p = vec.begin();
}
为什么此示例中需要“typename”关键字?是否还有其他必须指定“typename”的情况?
3 回答
简短回答:每当引用一个依赖名称的嵌套名称时,即嵌套在具有未知参数的模板实例中 .
答案很长:C中有三层实体:值,类型和模板 . 所有这些都可以有名称,仅凭这个名称并不能告诉你它是哪一层实体 . 相反,必须从上下文推断出有关名称实体性质的信息 .
无论什么时候推断都是不可能的,你必须指定它:
这里名称
Magic<T>::gnarl
,Magic<T>::brugh
和Magic<T>::kwpq
必须被解释,因为无法判断:由于Magic
是一个模板,Magic<T>
类型的本质取决于T
- 可能存在与主模板完全不同的特化, 例如 .是什么让
Magic<T>::gnarl
成为一个从属名称是因为我们在模板定义中,T
是未知的 . 如果我们使用Magic<int>
,这将是不同的,因为编译器知道(你保证!)Magic<int>
的完整定义 .(如果你想自己测试一下,这里有一个你可以使用的
Magic
的示例定义 . 原谅在专业化中使用constexpr
以简洁;如果你有一个旧的编译器,请随意将静态成员常量声明更改为旧的式前C 11表格 . )用法:
需要
typename
关键字,因为iterator
是P
上的依赖类型 . 编译器无法猜测iterator
是指一个值还是一个类型,所以它假定它是一个值,除非你大喊typename
. 只要存在依赖于模板参数的类型,在类型或值有效的上下文中就需要它 . 例如,由于基类必须是类型,因此不需要基类typename
.在同一主题上,有一个
template
关键字用于让编译器知道某些从属名称是模板函数而不是值 .每当类型名称依赖于模板参数时,都需要typename关键字(因此编译器可以_1119525_标识符(类型或值)的语义,而在第一次传递时没有完整的符号表) .
在使用通用模板参数时,单独的typename关键字也不是相同的含义,并且有点不太常见:http://ideone.com/amImX