在大多数情况下class和typename是没有区别的,只不过在涉及嵌套从属类型会涉及到两者的差别,具体情况是什么,后文讲解
嵌套从属类型
我们假设有一个场景,我们需要设计一个Print打印函数,这个函数需要用于各种容器,那么首先这是泛型编程,Print需要是函数模板,我们思考到,所有容器都能够通过迭代器遍历,所以我们需要使用这些容器中的迭代器进行迭代打印:
template<class Container>
void Print(const Container& v)
{
Container::const_iterator it = v.begin();
while (it != v.end())
{
cout << *it << ' ';
it++;
}
cout << endl;
}
于是就有上述代码,但是我们会发现,这段代码会报错
其原因在于,对于这种模板参数Container来说,我们通过域作用限定符:: 去访问到const_iterator,const_iterator可能是一个静态成员变量,也可能是typedef的内嵌类型或者是类部类类型,而编译器是默认不做任何修饰时将const_iterator解析为静态成员变量,所以此时,就需要用typename去修饰Container::const_iterator,让编译器认为它是一个类型,而非变量
template<class Container>
void Print(const Container& v)
{
typename Container::const_iterator it = v.begin();
while (it != v.end())
{
cout << *it << ' ';
it++;
}
cout << endl;
}
这样就就能够正常的运行了,上面的嵌套从属类型是体现在,使用了从属于Container模板类中的类型const_iterator
除了上面这种场景,还有如下场景
template<class T>
void Print(const vector<T>& v)
{
typename vector<T>::const_iterator it = v.begin();
while (it != v.end())
{
cout << *it << ' ';
it++;
}
cout << endl;
}
也就是说嵌套从属类型中有模板类型,就需要用typename进行修饰
那么关于我们就是想要用模板调用容器的静态成员变量的例子如下:
class AA
{
public:
AA(){}
static int _st;// 静态成员变量
};
template<class Container>
class BB
{
public:
void fun(int st)
{
Container::_st = st;//在BB中对Container这个模板中的_st变量进行赋值
cout << Container::_st << endl;//打印这个值
}
};
int AA::_st = 1;// 静态成员变量的声明(静态成员变量的声明是只能在全局域)
void test4()
{
BB<AA> b;//Container是AA
b.fun(10);
}
解释在注释中