本篇继续模版的学习
在定义模版的时候需要用到template 关键字,那还有其他用处么?有的,对于c++ 编译器,如何区分 '<' 和'>'是 模版的类型还是比较符号呢?对于c++,如果没有template名字,那么就认为是比较符号,有template,就认为是 模版类型。见下面的例子:
template<typename T>
class Shell {
public:
template<int N>
class In {
public:
template<int M>
class Deep {
}; };
public:
virtual void f();
};
template<typename T, int N>
class Weird {
public:
void case1 (
typename Shell<T>::template In<N>::template Deep<N>* p) { p->template Deep<N>::f(); // inhibit virtual call
}
void case2 (
typename Shell<T>::template In<N>::template Deep<N>& p) {
p.template Deep<N>::f(); // inhibit virtual call }
};
对于p->template Deep<N>::f();
,如果没有template,那编译器就会认为是 p-> ((Deep<N) > ::f() )
。
顺便提一下 typename,如果要强调某个名字就是类型,那就需要使用typename关键字。
ADL(argument dependent lookup):C++ 按照依赖的名字查询符号机制,可以通过名字的依赖找到并不在查询范围内的符号。 POI(point of instantiation): C++按照模版替换参数生成代码的位置
编译器遇到POI就去实例化,让链接器去重。
将实例化信息记录到一个数据库里,编译器在编译的时候查询数据库,已经实例化了就不去生成了
编译的时候不负责实例化,在链接的时候去迭代地实例化
目前编译器基本都是按照Greedy Instantiation 实现的。
可以讲模版声明和模版定义拆开,如下所示:
// translation unit 1:
template<typename T> void f(); // no definition: prevents instantiation
void g() {
f<int>(); }
// translation unit 2: template<typename T> void f() {
// implementation
}
template void f<int>();
void g();
int main() {
g(); }
// manual instantiation
这种做法虽然的确可以避免多次实例化,不过在实际中不推荐,因为需要显式实例化各种case,对于大的工程,维护成本太高。