模板中头文件和源文件的处置方式

通常写法,函数模板、类模板、变量模板不能分文件。其原因在于模板必须使用了才会生成实际的代码,才会有符号让链接器去链接。

只有实例化模板,编译器才能生成实际的代码,而我们之前只在头文件这种实现方式,是因为编译器根据我们的使用,知道我们需要什么类型的模板,生成实际的代码,比如实际的函数,实际的类,实际的变量等,然后再去调用。编译器的这种行为,我们称之为“隐式实例化模板”。

既然搞清楚这个原理,那将模板定义放在头文件,实现放在源文件也就成为可能。

函数模板显示实例化

源文件中:显示实例化定义

1
2
template 返回类型 名字 <实参列表>(形参列表);
template 返回类型 名字 (形参列表);

头文件中:显示实例化声明

1
2
extern template 返回类型 名字 <实参列表>(形参列表);
extern template 返回类型 名字 (形参列表);

在模板分文件问题中,几乎不会使用到显式实例化声明。因为我们引用 .h 文件本身就有声明。

显式实例化定义强制实例化它所指代的函数或成员函数。它可以出现在程序中模板定义后的任何位置,而对于给定的实参列表,它在整个程序中只能出现一次,不要求诊断。

显式实例化声明(extern 模板)阻止隐式实例化。本来会导致隐式实例化的代码必须改为使用已在程序的别处所提供的显式实例化。

不含实参列表

TemplateStudy.h

1
2
3
4
5
6
7
#ifndef STUDY__TEMPLATESTUDY_H_
#define STUDY__TEMPLATESTUDY_H_

template<typename T>
T add(T num1, T num2);

#endif //STUDY__TEMPLATESTUDY_H_

TemplateStudy.cpp

1
2
3
4
5
6
7
8
9
10
#include "TemplateStudy.h"

template<typename T>
T add(T num1, T num2){
return num1 + num2;
}

// 显式实例化
template int add(int, int);
template double add<dou(double , double);

main.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <iostream>
using namespace std;

#include "TemplateStudy.h"

int main() {

int result1 = add(3, 4); // 调用 add<int, int>
double result2 = add(3.5, 4.2); // 调用 add<double, double>

std::cout << "Result 1: " << result1 << std::endl;
std::cout << "Result 2: " << result2 << std::endl;

return 0;
}

含有实参列表

TemplateStudy.cpp

1
2
3
4
// 显式实例化

template int add<int>(int, int);
template double add<double>(double , double);

类模板显示实例化

类关键词 class,struct 或 union

源文件中:显示实例化定义

1
template 类关键词 模板名 < 实参列表 > ;	

头文件中:显示实例化声明

1
extern template 类关键词 模板名 < 实参列表 > ;	

 

TemplateStudy.h

1
2
3
4
5
6
7
8
9
10
#ifndef STUDY__TEMPLATESTUDY_H_
#define STUDY__TEMPLATESTUDY_H_

template<typename T>
class Test{
public:
T add(T num1,T num2);
};

#endif //STUDY__TEMPLATESTUDY_H_

TemplateStudy.cpp

1
2
3
4
5
6
7
8
9
#include "TemplateStudy.h"

template<typename T>
T Test<T>::add(T num1, T num2) {
return num1 + num1;
}

template int Test<int>::add(int num1, int num2);
template double Test<double>::add(double num1, double num2);

main.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>
using namespace std;

#include "TemplateStudy.h"

int main() {

Test<int> intTem;
Test<double> doubleTem;
int result1 = intTem.add(3, 4); // 调用 add<int, int>
double result2 = doubleTem.add(3.5, 4.2); // 调用 add<double, double>

std::cout << "Result 1: " << result1 << std::endl;
std::cout << "Result 2: " << result2 << std::endl;

return 0;
}