引言
本文探讨 C++ 模板编程中的两个关键问题。第一部分介绍 typename 在模板中的特殊使用场景,指出当模板参数访问内嵌类型时必须使用 typename 关键字来消除编译器歧义。第二部分分析模板分离编译导致链接错误的原因,通过对比普通函数和模板函数的编译链接过程,解释模板定义必须放在头文件中才能被实例化的原理。
1. 关于 typename 的使用场景
在模板参数定义时通常使用 typename 或 class,但在一些场景下,必须用 typename。例如编写通用打印容器的函数模板:
#include <iostream>
#include <vector>
#include <list>
using namespace std;
template<class Container>
void Print(const Container& con) {
typename Container::const_iterator it = con.begin();
while(it != con.end()) {
cout << *it << " ";
it++;
}
cout << endl;
}
int main() {
vector<int> v = {1, 2, 3, 4, 5, 6};
list<int> lt = {1, 2, 3, 4, 5, 6};
Print(v);
Print(lt);
return 0;
}
这里的 Container 可以是任意容器。运行上述代码会报错,原因在 Container::const_iterator it = con.begin(); 这句。因为模板的缘故,编译器从上往下编译到这句时并不知道 Container 是什么。如果按代码写法可能是命名空间或类,但编译器认为这里可能不合法:const_iterator 有可能是类型,也有可能是变量。如果是类型则合法,如果是变量则不合法。这里我们是一个类,const_iterator 可能是内部类或 typedef 定义的类型,符合语法要求;但也可能是静态成员变量(访问静态成员变量通过类名::静态成员),此时就不合法。


