2012年(158)
分类: C/C++
2012-11-26 15:54:24
template<typename T> struct
foo;
和
template<class T> struct
foo;
是等价的。
即告诉模板T是一种类型时,可以用class,也可以用typename。
这是因为C++标准一开始时都用class,后来发现typename这个关键字必不可少,于是有了重复功能。
template
struct foo
{
T::type*
type;
};
其中 T::type* type 是什么意思?编译器完全不知道,可能是
T::type(T中一个静态成员变量名叫type) *(乘以) type(一个全局变量名)
也可能是
T::type(T中定义的一个类型名叫type)*(指针形式)
type
有歧义的话,编译就进行不下去了。于是得明确告诉编译器T::type是个类型,于是写成
template
struct foo
{
class T::type*
type;
};
如果T::type是个自定义的类型(class/struct皆可)那自然没问题,类似于
class cls
{};
class cls obj; // 在C++中习惯省掉class,直接写成 cls obj;
在C中则必须加上
但假如是内建的int类型那就成了
class int
obj;
所以到此必须引入关键字typename,告诉编译器后面是个类型名,不管它是自定义类型还是内建类型。正确的代码应该是
template
struct foo
{
typename T::type*
type;
};
总结一下,关键字typename就是告诉编译器后面是个类型,否则编译器优先认为它是一个“非类型”。
当然,在某些场合下,它不可能是一个“非类型”,即无歧义的场合中,typename是不可以加上的,例如:
struct
X
{
X( int )
{
}
};
struct Y
{
typedef X
type;
};
template
{
foo() : T::type(0)
{
}
};
在(仅在)模板中,看起来似乎typename可以完全取代class,但看如下代码
template
{
};
template< template
{
};
foo
其中的class可以替换为struct和typename吗?自然不行,struct不像typename有作模板参数的功能,typename不像class/struct有作自定义类型的功能。
typename是用来消除歧义的,但有歧义的不仅是这一种,睇代码:
template
{
C::sub
};
其中 < 是
小于号,还是<>整体的前半部分?编译器优先认为是后者。
所以得在前面加上template告诉编译器C::sub是个模板。看一个复杂些的事例:
struct
foo
{
typedef int type;
template
struct sub
{
};
};
template
{
typename C::template
sub<typename C::type> val;
};
int main()
{
foo
return 0;
}
C::type前要加typename,告诉编译器C::type是个类型名
sub
C::template sub
自此文章结束,但某些用VC的人可能说:某些代码不加typename/template在VC中依然无错。这是因为VC对模板使用了“后编译”,看如下VC代码:
template
{
foo()
{
C::sub
}
};
struct A
{
typedef int type;
template
struct sub
{
};
};
struct B
{
static const int sub = 0;
static const int type =
0;
};
int val = 0;
int main()
{
foo a;
foo b;
return 0;
}
在foo中 C::sub