【C++20】vs2019使用modules的实际操作
????????
目錄
一、什么是modules
二、vs版本要求
三、項目配置
四、標準庫模塊引入方式
五、兼容舊式寫法
六、導出類與變量
七、文件后綴
八、實現與主接口分開
九、模塊命名與分區
十、引入模塊
十一、模塊分區? ? ? ?
十一、模塊私有部分
十二、結語
????????大家好,我是略游。今天講一講我在vs上操作C++20新標準模塊(modules)的經驗。此文章具有時效性,只代表當前實驗結果,也可作為一個基本寫法入門,將來的編譯器一定會完善得更好。
一、什么是modules
????????modules是C++20標準的源碼組織方式,以替代#include等傳統的源碼組織方式。與它相關的基本知識網上有很多文章,廢話不多說直接實際操作。
二、vs版本要求
????????官方文檔說16.10版本以上,更新最新版本即可。使用vs2022也可,不過需要注意的是需要安裝以下工具:
????????雖然在隨后的實驗中,我沒有成功使用上標準庫的模塊接口,但這個工具是否必須安裝,我暫時懶得測試了,在這里獲取工具:
三、項目配置
? ? ? ? 首先設置C++語言標準為/std:c++ latest,并且啟用標準庫模塊:
? ? ? ? ?在定義使用最新特性的命令行/await:
? ? ? ? ?在鏈接器中關閉使用增量鏈接,同時使用程序數據庫,這二者是配套的,如果不關閉增量鏈接,會與模塊編譯有沖突,后者不能正常識別修改。
四、標準庫模塊引入方式
? ? ? ? 按照微軟文檔的說法,如下即可導入標準庫模塊:
import std.core; import std.filesystem; //...? ? ? ? ?但實際操作中很困難,會提示一些編譯選項沖突。除了/EHsc和/MD選項,還有一些其他的定義沖突,例如_DEBUG宏。
? ? ? ? 文檔鏈接如下:
Overview of modules in C++ | Microsoft Docs
五、兼容舊式寫法
? ? ? ? 要以#include包含舊式頭文件,可以如下寫:
module; #include "Head.h" export module Test;? ? ? ? 這里包含了一個頭文件Head.h,然后導出了一個模塊叫Test。但是此處有一些局限性,Head.h不能是預編譯頭,預編譯頭是msvc的一種加快編譯速度的方式,但是這里是不能兼容的。
? ? ? ? 在Head.h里面我包含了一大串頭文件,這樣我們也能使用上標準庫。當前這樣的寫法,缺點是每次修改都需要重新編譯所包含的頭文件內容。預編譯頭可以解決這個問題,等完全使用上模塊后,也能解決這個問題。現在只是兼容的寫法。
//Head.h #pragma once #include <array> //!< 數組 #include <list> //!< 鏈表 //more...? ? ? ? ?值得一提的是,我在包含windows頭文件時,遇到一些報錯無法解決,最后只好不直接包含windows頭文件了,暫時使用傳統方法隱藏起來。
? ? ? ? 語法很簡明,在“module;”和“export module Test;”之間就是舊式的包含頭文件方式。
六、導出類與變量
? ? ? ? 前面加export即可導出類與全局變量,如下:
module; #include "Head.h" export module Test;export class Test {//... };export Test g_test;? ? ? ? ?這里就不用再像以往一樣,害怕變量重定義,不能直接放置到頭文件。在以前的寫法就是這樣的:
//--------------Test.h #include "Head.h"class Test {//... };extern Test g_test;//--------------Test.cpp Test g_test;? ? ? ? 另外constexpr常量并不能直接導出,因為它是不變量,在編譯期就會替換為數值,并不會真實存在這個變量,只能通過命名空間間接導出。
//-----------failed export constexpr size_t DEFINE_NUM_GOODS_00 = 16 * 22;//-----------ok export namespace Define {constexpr size_t NUM_GOODS_00 = 16 * 22; }七、文件后綴
? ? ? ? C++標準沒有規定文件的后綴名必須是什么,但是到目前為止,msvc必須使用.ixx后綴名,否則編譯器會報錯。
? ? ? ? 同時還應該設置文件項類型為C/C++編譯器?,如下圖所示:
? ? ? ? ?為了區分主接口文件,我們可以讓實現文件后綴為.cpp,但仍然注意屬性頁里的項類型也要是C/C++編譯器。
? ? ? ? 直接右鍵添加一個模塊文件,這樣也是正確的:
八、實現與主接口分開
? ? ? ? 我們可以直接在主接口文件實現Test::Init成員函數的定義,但也可以分開文件存放。例如以下文件Test.cpp,在兼容舊寫法的同時,還需表明自己是Test模塊的一部分。
module; #include "Head.h" module Test;void Test::Init() { }? ? ? ? 在以前的寫法,將函數定義在頭文件的嚴重缺點就是,修改此函數就會導致整個文件被修改,然后所有包含此文件的源碼都需要重新編譯。而模板函數必須放在頭文件,不但編譯速度極慢,而且無法規避這個問題。而使用模塊后便可以改進這個缺點,同時我們還能保持文件分開以保證代碼的整潔性。
九、模塊命名與分區
? ? ? ? 在一些示例中我們可以看到用點來分隔名字,比如export module Test.A,但實際上Test.A就是一個模塊的名字,它是一個整體,并不代表Test模塊的A分區(點在這里沒有任何意義,只是為了好看)。正規的分區寫法如下:
//Test.A是一個獨立的模塊 export module Test.A;//A是Test的分區 export module Test:A;? ? ? ? 另外微軟推薦文件名命名與模塊名相似,假設一個模塊叫Test.Point:Draw,那么它的文件名應該是Test.Point-Draw.ixx,實現文件可以叫Test.Point-Draw.cpp。即用-來代替:。
十、引入模塊
? ? ? ? 很簡單,如下寫即可:
import Test;? ? ? ? 如果想要“轉發”模塊,在自己引入X的時候,同時引入自己的地方也會引入X,如下所示:
export module Test;export import Test.Image; export import Test.Sprite; export import Test.Tex; export import Test.Text; export import Test.UI;? ? ? ? ?當另一個文件引入Test時,就不需要再引入Test.Image等了,只需import Test就會import Test.Image等。注意這里的.只是名字的一部分,而不是模塊分區,只是為了好看。
? ? ? ? 如果只是Test自己使用,去掉export則不會轉發:
export module Test;import Test.Image; import Test.Sprite; import Test.Tex; import Test.Text; import Test.UI;十一、模塊分區? ? ? ?
????????前面用“.”來分隔名字只是一種權宜手段,它們本質上是單獨的模塊,其余文件不需要通過Test來導入Test.Image,可以直接導入Test.Image。而分區模塊如果主接口沒有導出,則其他文件是使用不了的。
? ? ? ? 假設有個Test:Struct分區,在Main.cpp想要導入。那么這么寫是無效的:
import Test:Struct; //error? ? ? ? ?而用.的話,就可以:
import Test.Image; //ok? ? ? ? ?所以用分區的區別在于此,并且從定義上來說Test:Image是真正屬于Test的。
????????要定義一個模塊分區,如下:
export module Test:Struct;export struct A {//... };????????在上面的代碼,在Test:Struct分區導出了一個類A。在Test主接口文件,同樣可以選擇import或者export import。這決定了Test:Struct是否對外界可見。
//導出模塊Test export module Test;//導入Define import Define;//導入Test.Image并且使導入Test的自動導入Test.Image export import Test.Image;//導入Test.Ui供自己使用 import Test.UI;//導入分區,但是不導出,也可以前面加export導出 import :Struct;? ? ? ? 注意import模塊分區時,則必須省略冒號前面的模塊名, 想必編譯器也是由此判斷的。因為不屬于Test的模塊會import Test:Struct,然而這是不允許的。而屬于Test的模塊,是知道自己在Test的,所以可以省略“:”前的Test。
十一、模塊私有部分
? ? ? ? 在聲明module :private之后的內容只對自己文件可見,當然這是對于實現文件和模塊分區來說的。因為一個類或變量是否導出,取決于前面是否有export關鍵字。
module :private;十二、結語
????????如果你覺得此文章有幫到你,可以點擊收藏,然后點擊關注,這可以極大的支持我發更多的文章。
? ? ? ? 你還可以加我的QQ群討論:游戲編程星云閣?170100866
?
與50位技術專家面對面20年技術見證,附贈技術全景圖總結
以上是生活随笔為你收集整理的【C++20】vs2019使用modules的实际操作的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【C++】Visual studio样式
- 下一篇: s3c2440移植MQTT