C++98 模板中的依赖名称(Dependent Names)
在C++98中,模板编程中有一个重要的概念叫“依赖名称(Dependent Name)”。依赖名称指的是那些在模板中无法在编译期直接解析的名称,因为它们的含义依赖于模板参数的具体类型或值。
依赖名称的分类
依赖名称主要分为两类:
-
类型依赖名称(Type-dependent names)
这些名称的具体类型取决于模板参数。例如:template<typename T> struct Wrapper { typedef typename T::value_type nested_type; };
在这个例子中,
T::value_type
是一个依赖名称,因为只有在实际使用Wrapper
时,T::value_type
的具体含义才能确定。 -
值依赖名称(Value-dependent names)
这些名称的值取决于模板参数的值。例如:template<int N> struct Increment { static const int value = N + 1; };
在这里,
N + 1
是值依赖名称,因为N
是一个模板参数,只有在模板实例化时才能知道其具体值。
需要显式标注的情况
C++98标准中,编译器在处理依赖名称时有一定限制,许多情况下需要开发者显式地标明某个名称是类型还是模板。常用的两种标注方式是:
-
typename
关键字
typename
用于告诉编译器某个依赖名称是一个类型。例如:template<typename T> struct Wrapper { typedef typename T::value_type nested_type; };
如果不加
typename
,编译器可能会误认为T::value_type nested_type
是一种成员变量声明,而不是类型别名。 -
template
关键字
template
用于告诉编译器某个依赖名称是一个模板。例如:template<typename T> void invokeMember(T t) { t.template memberTemplateFunction<int>(); }
如果不加
template
,编译器可能会认为memberTemplateFunction
是一个普通成员函数或者成员变量。
使用 template
关键字调用基类模板成员函数
在继承关系中,派生类通常需要访问基类的成员函数。如果这些成员函数本身也是模板函数,并且基类依赖于模板参数,那么在调用时需要明确指出这些函数是模板。