模塊(modules)
C++20 引入了模塊(modules),這是自 C++11 引入的範本(templates)以來最大的語言特性改變之一。 模塊旨在替代傳統的頭文件機制,以改善編譯時間並提供更好的封裝性。
傳統的 c++ include 真的好難用喔,像 python 都可直接 import 模組使用 ex: import numpy as np
我們來看一下 include 造成的問題吧
傳統 include 的問題
編譯時間過長
重複解析:每次編譯器處理一個源文件時,會重新解析並處理所有包含的頭文件。這些頭文件可能包含大量重複的代碼,導致編譯時間增加。
依賴關係複雜:頭文件的嵌套包含關係複雜,可能導致多個頭文件被多次包含,進一步增加編譯時間。
宏污染
命名衝突:頭文件中使用的宏定義可能會污染全局命名空間,導致意外的命名衝突和難以排查的錯誤。
不可控的依賴
依賴傳播:一個頭文件包含另一個頭文件,依賴關係會逐層傳播,導致編譯單元的依賴關係變得非常複雜和不可控。
封裝性差
內部實現洩露:頭文件通常會暴露實現細節,破壞封裝性。任何對頭文件的修改都會迫使所有依賴它的文件重新編譯。
模塊(modules)如何解決這些問題
減少編譯時間:
- 一次性解析:模塊只需解析和編譯一次,然後可以被多次導入,而無需重複解析。這顯著減少了編譯時間。
- 模塊化邊界:模塊引入了更明確的邊界,減少了不必要的依賴傳播。
消除宏污染:
命名空間隔離:模塊不直接使用宏,從而避免了命名衝突和全局命名空間污染的問題。
簡化依賴管理:
清晰的依賴關係:模塊導入的依賴關係更加明確,減少了依賴傳播,從而使依賴管理變得更加簡單和可控。
提高封裝性:
隱藏實現細節:模塊可以更好地封裝實現細節,只導出必要的接口。這樣,內部實現的改動不會迫使所有依賴的文件重新編譯。
Demo 在 VS2022 使用 Module
在 VS2022 使用 Module 很容易 首先,先在語言的地方選擇 c++20, 否則編譯會失敗 (Visual Studio 2019 版本 16.8 及以上,或者 Visual Studio 2022,這些版本支持 C++20 模塊)
新增項目
選 C++ 模組介面單位(.ixx)
filename:math.ixx 我們定義了 function , class, struct
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
export module math;
export int add(int a, int b) {
return a + b;
}
export class Math {
public:
int add(int a, int b);
int subtract(int a, int b);
};
export struct Point
{
int x;
int y;
};
filename:math_impl.cpp 開頭需指名要實作的模組 class 實作部分
1
2
3
4
5
6
7
8
9
module math;
int Math::add(int a, int b) {
return a + b;
}
int Math::subtract(int a, int b) {
return a - b;
}
main function 開頭 import 模組 math
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import math;
#include <iostream>
int main()
{
std::cout << "Hello World!\n";
int result = add(5, 3);
std::cout << "Result: " << result << std::endl;
Math math;
std::cout << "math.add(5,3): " << math.add(5,3) << std::endl;
std::cout << "math.subtract(5,3): " << math.subtract(5,3) << std::endl;
Point p{ .x = 0, .y = 10 };
std::cout << p.x << " " <<p.y<< std::endl;
return 0;
}
檔案如同下面顯示
很簡單吧! Happy coding!