我已经习惯于在课堂模板中强制使用typename
,但不能不知道是否真的有必要。这个问题在here on SO之前被问过,但我对答案并不满意(如果我理解正确的话也不是OP)。
当和 时,完全清楚(来自cppreference.com):
在模板的声明或定义中,包括别名模板,除非使用关键字typename或除非使用关键字typename,否则不是当前实例化成员且依赖于模板参数的名称不被视为类型它已经建立为类型名称,例如使用typedef声明或用于命名基类。
当定义(类或函数)模板(尚未实例化)时,我理解该语句
A::Type *tp;
其中A
是模板类型参数,Type
应该是嵌套类型,不明确。 Type
也可能是静态成员或枚举值,或者我现在无法想到的任何其他可能性。在这种情况下,*
运算符是乘法(假设"乘法"是operator*()
的实现的正确措辞)而不是指针声明。但是,我不能想到这样的语句可以代表类范围中的乘法的任何情况。在函数范围内,当然,除了指针声明之外,这在类范围内意味着什么呢?
我的观点是,在许多情况下,编译器在某个时刻需要一个类型名称,但我们仍然要求我们明确指定它,即使没有其他选项。 GCC和Clang都发出错误而非警告这一事实非常具有说明性:
template <typename T>
struct A
{
T::x *p;
};
GCC: error: need ‘typename’ before ‘T::x’ because ‘T’ is a dependent scope
CLANG: error: missing 'typename' prior to dependent type name 'T::x'
另一个引人注目的案例(至少对我来说)是使用typedef
s来为别名类别设置别名。在这种情况下,毫无疑问typedef
关键字后面的内容是否应该是一种类型(对吗?),为什么要消除歧义呢?
总结一下:在很多情况下编译器可以很容易地从语法和上下文中推断出程序员是指类型还是变量,为什么还需要消除歧义?
修改
评论和建议的重复提及专业化可能使问题复杂化。例如(取自另一个帖子中的答案):
struct B {
typedef int result_type;
};
template<typename T>
struct C { }; // could be specialized!
template<typename T>
struct D : B, C<T> {
void f() {
// OK, member of current instantiation!
// A::result_type is not dependent: int
D::result_type r1;
// error, not a member of the current instantiation
D::questionable_type r2;
// OK for now - relying on C<T> to provide it
// But not a member of the current instantiation
typename D::questionable_type r3;
}
};
我理解C
可能专门针对T
,C<T>::questionable_type
是否存在只能在实例化时解决,但这并不会改变它 是一种类型。语法只是要求它,所以为什么要消除歧义?