在编写模板的时候,刚开始是将模板定义在头文件,当具体实现是在cpp文件,发现编译没通过.
后发现一篇知乎的提问,好像模板不支持定义和实现分离,应该是需要直接编写在头文件
知乎提问链接:https://www.zhihu.com/question/20630104
template中使用typename
如下:
template<typname T>
void test(T t) {
T::Test test;
test.print();
}
在这个模板函数中,T因为可以传递是任意类型,那么T::Test在实例化的时候,就可能存在Test是T的静态成员变量,或者Test是T中的父类或者其内部定义的一种类型。
那么这就会存在歧义,而用typename T::Test test;声明该模板只能应用于Test为其父类或者其内部定义的一种类型。编译通过。
template中使用typedef typename,
通过上面的也大致可以猜测到其作用,
如
template<typename T>
void test(T t) {
typedef T::Test Test;
Test test;
test.test();
}
这里同样会出现相应的歧义,那么这个Test::Test是什么类型呢,同样是不确定,那么通过typename,来指定这个是一个类类型即可
即typedef typename T::Test Test;
template中使用typedef typename ::template的情况,
有时候我们再查看stl源代码的时候,会发现这种奇特的代码,
如下:
template<typanem T>
class A {
public:
template<typename D>
struct Test {
void test() {}
};
};
template<typename T, typename D>
void test() {
typedef typename A<T>::template Test<D> Test;
Test test;
test.test();
}
上面这段代码中存现typedef typename A<T>::template Test<D> Test;其目的是希望将A中的Test类型,缩写为Test,方便后面直接使用,
但是如果我们直接typedef A<T>::Test<D> Test是不行的
1.第二个<D>会被认为是小于号,不会作为模板语法来解析。(通过A<T>::template Test<D>来解决)
2.正确上面的一样::Test并不能确定Test是哪一种类型。(通过增加typename来解决)
另一个原因是,虽然实际在使用的时候需要在编译器确定具体的类型值,但是在模板定义的时候,各个类型的在这个模板中应该是一个什么类型就应该要被确定了,
而这个确定不是要等待模板特例化的时候在动态根据实际参数做出变化的。