模板最初的目的只是为了对类类型进行泛型操作的定义,因此用class关键字声明泛型类型。在之后的进化过程中发现了模板相互调用时产生的::操作符有二义性,即编译器不能判定::后的标示符是类的类型成员,还是类的数据成员,默认情况下,编译器假定这样的标示符指定的是数据成员,而不是类型。因此引入typename关键字用于告诉编译器将::符号后的标示符看作是类型,而且必须显式告诉。
template<class T, int N>
class Test
{
public:
typedef T ElemType;
enum{ LEN = N };
ElemType array[LEN];
};
/************************************
如果要在函数模板内部使用在类中定义的类型成员(ElemType),
必须在该成员名前加上typename关键字,以告知编译器将该成员当做类型
************************************/
template<class T>
void test_copy( T& test, typename T::ElemType a[], int len )
{
int l = (len < T::LEN) ? len : T::LEN;
for(int i=0; i<l; i++)
{
test.array[i] = a[i];
}
}
int main( )
{
Test<int, 5> t1;
Test<float, 3>t2;
int ai[] = {5, 4, 3, 2, 1, 0};
float af[] = {0.1, 0.2, 0.3};
test_copy(t1, ai, 6);
test_copy(t2, af, 3);
for(int i=0; i<t1.LEN; i++)
{
cout<<t1.array[i]<<endl;
}
for(int i=0; i<t2.LEN; i++)
{
cout<<t2.array[i]<<endl;
}
cout<<"Press the enter key to continue........";
cin.get();
return 0;
}
因此如果拿不准是否需要以typename指明一个名字是一个类型,那么显式指定它是个好主意。在类型之前指定typename没有害处,因此,即使typename是不必要的,也没有关系。