> For the complete documentation index, see [llms.txt](https://mq-bai.gitbook.io/modern-cpp-templates-cookbook/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://mq-bai.gitbook.io/modern-cpp-templates-cookbook/07-xian-shi-shi-li-hua-jie-jue-mu-ban-dao-chu-jing-tai-dong-tai-ku.md).

# 显式实例化解决模板导出静态动态库

## 前言

我们使用显式实例化解决模板导出动态静态库这个问题，原因什么的不再过多赘述，总结一句话：

* **模板需要实例化才能生成实际的代码，既然不能隐式实例化，那就显式实例化**。

我们以 `windows` 环境 `VS2022`，`sln` 解决方案为例。

> 不再使用 cmake 主要是本课程也不是教你 cmake 的，这些东西有点麻烦，不如直接用 VS 按钮点点点设置就是。之前用 cmake 项目主要在于 **`add_executable`**，比较明确，说明编译哪些文件。

我们创建了一个[解决方案](https://github.com/Mq-b/Modern-Cpp-templates-tutorial/blob/main/code/05显式实例化解决模板导出动态静态库问题/05显式实例化解决模板导出动态静态库问题.sln)，其中有四个项目：

1. [**测试动态库使用**](https://github.com/Mq-b/Modern-Cpp-templates-tutorial/blob/main/code/05显式实例化解决模板导出动态静态库问题/README.md)
2. [**测试静态库使用**](https://github.com/Mq-b/Modern-Cpp-templates-tutorial/blob/main/code/测试使用静态库/README.md)
3. [**用模板生成动态库**](https://github.com/Mq-b/Modern-Cpp-templates-tutorial/blob/main/code/生成动态库/README.md)
4. [**用模板生成静态库**](https://github.com/Mq-b/Modern-Cpp-templates-tutorial/blob/main/code/生成静态库/README.md)

> 生成动态库和静态库用的代码几乎是一模一样的，只是去掉了 `__declspec(dllexport)`。

> 测试动态库和静态库使用的主要区别在于项目配置，代码上的区别是去掉 `__declspec(dllexport)`。

## 模板生成动态库与测试

[**`export_template.h`**](https://github.com/Mq-b/Modern-Cpp-templates-tutorial/blob/main/code/生成动态库/export_template.h)

```cpp
#pragma once

#include <iostream>
#include <string>

template<typename T>
void f(T);

template<typename T>
struct __declspec(dllexport) X {
    void f();
};
```

[**`export_template.cpp`**](https://github.com/Mq-b/Modern-Cpp-templates-tutorial/blob/main/code/生成动态库/export_template.cpp)

```cpp
#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)`](https://learn.microsoft.com/zh-cn/cpp/build/exporting-from-a-dll-using-declspec-dllexport?view=msvc-170)。

> 可以使用 \_\_declspec(dllexport) 关键字从 DLL 中导出数据、函数、类或类成员函数。

以上示例中的函数模板、类模板**显式实例化**，不要放在 `.h` 文件中，因为 **一个显式实例化定义在程序中最多只能出现一次**；如果放在 `.h` 文件中，被多个翻译单元使用，就会产生问题。

> 当显式实例化函数模板、变量模板 (C++14 起)、类模板的成员函数或静态数据成员，或成员函数模板时，**只需要它的声明可见**。

> **类模板、类模板的成员类或成员类模板在显式实例化之前必须出现完整定义**，除非之前已经出现了拥有相同模板实参的显式特化

我们将生成的 `.dll` 与 `.lib` 文件放在了[指定目录](https://github.com/Mq-b/Modern-Cpp-templates-tutorial/blob/main/code/05显式实例化解决模板导出动态静态库问题/lib/dll/README.md)下，配置了项目的查找路径以供使用。

[**`run_test.cpp.cpp`**](https://github.com/Mq-b/Modern-Cpp-templates-tutorial/blob/main/code/05显式实例化解决模板导出动态静态库问题/run_test.cpp.cpp)

```cpp
#include "export_template.h"
#include <string>

int main(){
    std::string s;
    f(1);
    //f(1.2); // Error!链接错误，没有这个符号
    f(s);
    X<int>x;
    x.f();
}
```

## 模板生成静态库与测试

没有多大的区别，原理都一样，代码也差不多，不必再讲。

## 总结

我们没有讲述诸如：项目如何配置，**怎么配置项目生成动态库、静态库**，这也不是我们的重点。在视频中我们会从头构建这些。但是文本的话，不必要从头教学这些基本知识。

我们关注代码上即可。

静态库也没有单独提，因为的确没啥区别。

另外如果你直接打开我们的项目，无法编译或许很正常，请自己根据当前环境，处理编码问题，以及生成动态静态库，配置，使用。
