在使用函数模板之前,编译器必须看到不仅仅是一个声明,通常编译器需要完整的函数模板定义。换句话说,如果你在头文件中定义了一个模板,那么这个头文件必须包含该函数模板的主体。
假设需要在许多项目之间共用某个函数foo
。通常情况下,会将函数声明放在一个头文件中,比如common.hpp
,并将完整的定义放在一个单独的源文件中,比如common.cpp
。
然而,当该函数为函数模板时,通常会将定义放在头文件中。这是为了让编译器从模板创建具体的函数,比如foo<int>
或foo<long>
,它需要函数模板的主体。
错误示例:
common.hpp
#pragma oncetemplate<class T>
T my_max(T a, T b);
common.cpp
#include "common.hpp"template<class T>
T my_max(T a, T b){return a > b? a: b;
}
main.cpp
// g++ -I. main.cpp common.cpp -O2
#include <iostream>
#include "common.hpp"int main() {std::cout << my_max<long>(12, 23U) << std::endl;std::cout << my_max<float>(42.f, 23U) << std::endl;
}
使用指令g++ -I. main.cpp common.cpp -O2
编译时提示如下错误:
/usr/bin/ld: /tmp/ccfkfBWe.o: in function `main':
main.cpp:(.text.startup+0x14): undefined reference to `long my_max<long>(long, long)'
/usr/bin/ld: main.cpp:(.text.startup+0x3c): undefined reference to `float my_max<float>(float, float)'
collect2: error: ld returned 1 exit status
如上错误就是因为没有用模板生成对应的函数定义,报未定义的引用的错误。
正确示例:
common.hpp
#pragma oncetemplate<class T>
T my_max(T a, T b){return a > b ? a: b;
}
main.cpp
// g++ -I. main.cpp -O2
#include <iostream>
#include "common.hpp"int main() {std::cout << my_max<long>(12, 23U) << std::endl; // 23std::cout << my_max<float>(42.f, 23U) << std::endl; // 42
}
通过在编译指令中加--save-temps
验证汇编代码中确实存在long
、float
两个版本的函数实现。
g++ -I. main.cpp --save-temps -O2
。