C++20的模块,高封装性,单次定义规则,是一项比较新的技术,我总结了一些规律,现记录下来。
我在VS2022中编写模块文件,需要开启C++20支持,模块的扩展文件是 .ixx 这种文件被自动识别为模块文件。
Module.ixx
module;
#include<iostream>
#include<cstdlib>
#include<thread>
#include<experimental/coroutine>
#include<ranges>
#include<vector>
#include<atomic>
#include<memory>
#include<functional>
export module Module;
import string;
import thread;
class Point {
//inline static const std::vector<int> arr = { 12,34,56,78,89,56,5634,534,56 };
public:
constexpr Point() { }
auto operator <=>(const Point& value) const = default;
consteval auto GetX() const {
// ....................
}
constexpr auto GetArr() const {
// .............
…
上面的这个示例呢,最开始的module表示一个全局模块的开始,由这个关键字开始的在其后面可以编写预处理器定义,再往下看,就是export module Module;这里就是我导出了一个全局模块,这个模块的名字叫Module,它可以被外部进行引入。下方的import string;就是我在其他的.ixx文件中导出的模块。
在模块导出时,我需要指定哪些需要被导出,对于我想要导出的类型,我可以在我的类型前面加入export
module;
export module string;
export class MyString final {
public:
static wchar_t* CharToWchar(const char* v1, wchar_t*& v2);
static char* WcharToChar(const wchar_t* v1, char*& v2);
static wchar_t* Utf8ToWchar(const char* v1, wchar_t*& v2);
static char* WcharToUtf8(const wchar_t* v1, char*& v2);
};
我在string模块中导出了一个类(MyString)。
如果你在阅读这个文章,你可能发现了不同处,上面的类只有声明,没有定义,是的!他的定义在其他的模块文件中。我将他的定义放在了模块string.core.ixx文件中,
module;
#include<Windows.h>
#include<assert.h>
module string; // 作为主模块的分区实现文件,可在其他分区使用。
class MyString
{
public:
static wchar_t* CharToWchar(const char* v1, wchar_t*& v2) {
assert(v1 != NULL);
if (v2 != nullptr) Free(v2);
int len = MultiByteToWideChar(CP_ACP, 0, v1, -1, NULL, 0);
v2 = new wchar_t[len];
MultiByteToWideChar(CP_ACP, 0, v1, (int)strlen(v1), v2, len);
v2[len - 1] = L'\0';
return v2;
}
………其他代码实现省略。
当我在写某一个模块的定义文件时,这就叫模块的分区文件,他作为string模块的分区实现文件,在开头预处理指令结束后,就需要声明模块,module string; 在编写定义的代码是,无需再次进行export,按照正常的逻辑编写即可,这个模块不需要导出,也不需要在其他的模块导入(私有模块);
如果我想要在其他的分区共享模块的分区文件,那么我可以这样编写:
export
module
MyModule:String;
//
作为主模块的分区实现文件,可在其他分区使用。
我在MyModule写定义,在String写实现,并且导出这个String模块分区,既然导出了,那么我就可以导入了,我在其他的模块分区想使用他,于是我编写了这个代码:
import
:String;
//
导入分区模块,分区实现文件可见。
前缀以冒号开头,表示一个分区模块。
在我编写这个文档的时候,模块技术还不是很成熟,标准库的模块支持,这个可以在项目属性中修改,以增加对模块标准库的访问:
以下示例是引用的标准库模块,有可能需要下载单个组件,支持模块标准库。
import MyModule;
#pragma warning(disable:5050) // 解除标准库模块头文件的警告。
import std.core;
int main()
{
std::cout << "hello,word" << std::endl;
return 0;
}