面试题答案
一键面试遇到的问题
当函数模板的声明和定义放在不同文件时,链接器在链接阶段会找不到模板实例化的代码。因为模板是在实例化时才生成具体代码,而编译器在编译源文件时,默认只处理当前文件的内容,不会跨文件查找模板定义。比如有一个template <typename T> void func(T t);
在头文件声明,template <typename T> void func(T t) { /* 具体实现 */ }
在源文件定义,当其他源文件调用func
时,编译器无法在调用处找到模板函数的实现,链接时就会报未定义的错误。
解决方法
- 将定义放在头文件中:直接把函数模板的定义和声明都放在同一个头文件中。这样,当其他源文件包含该头文件时,模板的声明和定义都能被看到,编译器可以在需要实例化的地方生成代码。例如:
// template_func.h
template <typename T>
void func(T t) {
// 函数实现
}
然后在其他源文件中包含此头文件即可使用func
。
2. 显式实例化:在包含模板定义的源文件中,对需要使用的模板类型进行显式实例化。例如:
// template_func.cpp
template <typename T>
void func(T t) {
// 函数实现
}
// 显式实例化
template void func<int>(int);
template void func<double>(double);
这样,编译器会为指定的类型生成模板实例化的代码,在链接时就不会出现未定义的错误。但这种方法需要提前知道会使用哪些类型进行实例化,不够灵活。
3. 使用export关键字(C++早期标准,现在已弃用):在模板声明和定义前加上export
关键字。例如:
// template_func.h
export template <typename T>
void func(T t);
// template_func.cpp
export template <typename T>
void func(T t) {
// 函数实现
}
这种方法允许编译器跨文件查找模板定义,但由于实现复杂且不同编译器支持不一致,在C++标准中已弃用。