在 C++ 中为了操作简洁引入了函数模板。所谓的函数模板实际上是建设一个通用函数,其函数类型或形参类型不具体指定,用一个虚构的类型来表白,这个通用函数就称为函数模板。
1、通用的写法
函数模板不是一个具体的函数,编译器不能为其生成可执行代码。定义函数模板后只是一个对函数性能框架的形容,当它具体执行时,将依据传递的理论参数决定其性能。为了容易应用,个别通用的写法都是在头文件中间接定义函数模板,定义的同时也是申明该函数,供应其它文件蕴含调用。
//------fun.h 或 fun.hpp------//
#ifndef _FUN_H_
#define _FUN_H_
using namespace std;
template<typename T>
void fun(int b, T c, T d) // 定义函数模板
{......}
#endif
对编译器而言,定义函数模板的时候,编译器并不会对它进行编译,因为它没有一个实体可用,编译器只看到了申明,只有模板被实例化后(用在特定的类型上),编译器才会依据具体的类型对模板进行编译。因而当在别的文件中调用该函数模板时,依据传递的理论参数决定其性能,这样编译器就能够在编译期间看到模板函数的定义并实现模板的实例化,如果在编译的时候,找不到模板函数的定义,就先不在这一次编译中实例化该模板函数。
2、问题的引出
然而头文件中定义和应用函数模板时,碰到了一个这样的场景,即在函数模板中应用到了全局变量:
//------fun.h 或 fun.hpp------//
#ifndef _FUN_H_
#define _FUN_H_
using namespace std;
int a; // 定义全局变量
template<typename T>
void fun(int b, T c, T d) // 定义函数模板
{
......
a = b;
}
#endif
因而碰到其它多个文件须要应用该函数模板时,都须要各自蕴含该函数模板的头文件,编译时就会呈现“全局变量反复定义”的谬误。
尝试依照一般函数定义和申明离开的思路将函数模板的定义和申明离开:
源文件:
//------fun.cpp------// // 错误做法
using namespace std;
int a; // 定义全局变量
template<typename T>
void fun(int b, T c, T d) // 定义函数模板
{
......
a = b;
}
头文件:
//------fun.h 或 fun.hpp------// // 错误做法
#ifndef _FUN_H_
#define _FUN_H_
extern a;
template<typename T> void fun(int b, T c, T d);
#endif
通过尝试,依照一般函数的形式将函数模板的定义和申明离开,在其它文件中调用函数模板,编译时就会呈现“找不到该函数定义”的谬误。
那么有没有方法将函数模板的定义和申明正确离开,提供给其它文件蕴含调用呢,答案必定是有的。
3、问题的解决
针对上述第 2 点所论述的函数模板应用的这一场景,须要将函数模板的定义和申明拆散开来,依据理论的利用,应用以下的做法能够很好的解决这一问题,编译和调用都没有问题。
首先是源文件 *.cpp 的实现:
//------fun.cpp------//
using namespace std;
int a; // 定义全局变量
template<typename T>
void fun(int b, T c, T d) // 定义函数模板
{
......
a = b;
}
template void fun(int b, int c, int d); // 函数模板实例化,此时 T 被 int 代替
template void fun(int b, char c, char d); // 函数模板实例化,此时 T 被 char 代替
因而在源文件中操作有:
(1)、定义须要应用的函数模板;
(2)、在定义的函数模板后进行函数实例化操作,通过这样的办法实现具体的模板函数。
接着是头文件 .h 或者 .hpp 的实现:
//------fun.h 或 fun.hpp------//
#ifndef _FUN_H_
#define _FUN_H_
extern a;
template<typename T> void fun(int b, T c, T d);
extern template void fun(int b, int c, int d);
extern template void fun(int b, char c, char d);
#endif
因而在头文件中须要的操作有:
(1)、申明定义的函数模板;
(2)、应用 extern 的形式申明实例化后的模板函数。
总结
可见,将函数模板的定义和申明离开,须要额定在源文件中进行函数模板的实例化再在头文件中进行申明,多了一些步骤。在无特定的应用的场景中,还是倡议将函数模板放在头文件中间接定义并调用;当然,如果碰到一些跨文件调用的特定场景,那么采纳这种将函数模板的定义和申明离开的办法也是 OK 的。
更多技术内容和书籍材料获取敬请关注公众号“明解嵌入式”