显式实例化解决模板导出静态库动态库
前言
我们使用显式实例化解决模板导出动态静态库这个问题,原因什么的不再过多赘述,总结一句话:
- 模板需要实例化才能生成实际的代码,既然不能隐式实例化,那就显式实例化。
我们以 windows
环境 VS2022
,sln
解决方案为例。
不再使用 cmake 主要是本课程也不是教你 cmake 的,这些东西有点麻烦,不如直接用 VS 按钮点点点设置就是。之前用 cmake 项目主要在于
add_executable
,比较明确,说明编译哪些文件。
我们创建了一个解决方案,其中有四个项目:
生成动态库和静态库用的代码几乎是一模一样的,只是去掉了
__declspec(dllexport)
。
测试动态库和静态库使用的主要区别在于项目配置,代码上的区别是去掉
__declspec(dllexport)
。
模板生成动态库与测试
#pragma once
#include <iostream>
#include <string>
template<typename T>
void f(T);
template<typename T>
struct __declspec(dllexport) X {
void f();
};
#include "export_template.h"
template<typename T>
void f(T) { // 函数模板定义
std::cout << typeid(T).name() << '\n';
}
template <typename T>
void X<T>::f(){ // 类模板中的成员函数模板定义
std::cout << typeid(T).name() << '\n';
}
template __declspec(dllexport) void f<int>(int);
template __declspec(dllexport) void f<std::string>(std::string);
template struct X<int>; // 类模板显式实例化
这很简单,和之前分文件写法的区别只是用了__declspec(dllexport)
。
可以使用 __declspec(dllexport) 关键字从 DLL 中导出数据、函数、类或类成员函数。
以上示例中的函数模板、类模板显式实例化,不要放在 .h
文件中,因为 一个显式实例化定义在程序中最多只能出现一次;如果放在 .h
文件中,被多个翻译单元使用,就会产生问题。
当显式实例化函数模板、变量模板 (C++14 起)、类模板的成员函数或静态数据成员,或成员函数模板时,只需要它的声明可见。
类模板、类模板的成员类或成员类模板在显式实例化之前必须出现完整定义,除非之前已经出现了拥有相同模板实参的显式特化
我们将生成的 .dll
与 .lib
文件放在了指定目录下,配置了项目的查找路径以供使用。
#include "export_template.h"
#include <string>
int main(){
std::string s;
f(1);
//f(1.2); // Error!链接错误,没有这个符号
f(s);
X<int>x;
x.f();
}
模板生成静态库与测试
没有多大的区别,原理都一样,代码也差不多,不必再讲。
总结
我们没有讲述诸如:项目如何配置,怎么配置项目生成动态库、静态库,这也不是我们的重点。在视频中我们会从头构建这些。但是文本的话,不必要从头教学这些基本知识。
我们关注代码上即可。
静态库也没有单独提,因为的确没啥区别。
另外如果你直接打开我们的项目,无法编译或许很正常,请自己根据当前环境,处理编码问题,以及生成动态静态库,配置,使用。