分享方式:


逐步解說:將 STL 程式庫匯入為標頭單元

本逐步解說示範如何在 Visual Studio 中將 C++ 標準範本庫 (STL) 程式庫匯入為標頭單元。 如需更快速且更可靠的方式來匯入標準程式庫,請參閱教學課程:使用模組匯入 C++ 標準程式庫

將 STL 標頭匯入為標頭單元比使用先行編譯標頭檔更簡單。 標頭單元更容易設定及使用,且在磁碟上大幅縮小、同時提供類似的效能優點,而且比共用 PCH 更有彈性。

如需哪些標頭單元及其所提供優點的詳細資訊,請參閱什麼是標頭單元?。 若要將標頭單元與其他匯入標準程式庫的方式進行對比,請參閱比較標頭單元、模組和先行編譯標頭檔

必要條件

若要使用標頭單元,請使用 Visual Studio 2022 或更新版本,或 Visual Studio 2019 16.11 版或更新版本。 使用標頭單元需要 /std:c++20 選項 (或更新版本)。

匯入 STL 標頭作為標頭單元的兩種方法

您必須先將 STL 標頭編譯為標頭單元,才能匯入 STL 標頭。 標頭單元是標頭檔的二進位表示法。 它具有 .ifc 延伸模組。

建議的方法是建立靜態程式庫,其中包含您想要使用之 STL 標頭的建置標頭單元。 然後參考該程式庫並 import 其標頭單元。 這種方法可能會導致更快速的建置及更好的重複使用。 若要試用此方法,請參閱方法 1:建立 STL 程式庫標頭單元的靜態程式庫

另一種方法是讓 Visual Studio 掃描您在專案中所 #include 的 STL 標頭,接著將其編譯成標頭單元,然後 import 而不是 #include 那些標頭。 如果您有大型程式碼基底,因為不需要變更原始程式碼,這個方法就很有用。 這種方法比靜態程式庫方法更不具彈性,因為它本身無法重複使用其他專案中的建置標頭單元。 但是,您仍然可以取得將個別 STL 程式庫匯入為標頭單元的效能優勢。 若要試用此方法,請參閱方法 2:針對要匯入的 STL 標頭掃描 Include

方法 1:建立 STL 程式庫標頭單元的靜態程式庫

使用 STL 程式庫作為標頭單元的建議方式是建立一或多個靜態程式庫專案。 這些專案應該包含您想要使用的 STL 程式庫標頭單元。 然後,參考程式庫專案以取用這些 STL 標頭單元。 這類似於使用共用先行編譯標頭,但比較容易。

靜態程式庫專案中內建的標頭單元 (和模組) 會自動可供參考專案,因為專案系統會自動將適當的 /headerUnit 命令列選項新增至編譯器,以便參考專案可以匯入標頭單元。

此方法可確保特定標頭的標頭單元只會建置一次。 它可讓您匯入部分或所有標頭單元,使用 PCH 時則無法。 您可以依任何順序包含標頭單元。

在下列範例中,您會建立靜態程式庫專案,其中包含 <iostream><vector> 標頭單元。 建置方案之後,您將從另一個 C++ 專案參考此共用標頭單元專案。 在任何地方找到 import <iostream>;import <vector>; 時,都會使用該程式庫的建置標頭單元,而不是使用前置處理器轉譯標頭。 當多個檔案中包含相同的標頭時,它可改善建置效能,如同 PCH 檔案。 標頭不一定會由包含它的檔案來回處理。 而是會匯入處理後的已編譯標頭單元。

若要建立包含 STL 程式庫 <iostream><vector> 的靜態程式庫,請遵循下列步驟:

  1. 建立空白 C++ 專案。 將其命名為 SharedPrj
    從 [建立新專案] 視窗中可用的專案類型選取 C++ 的 [空白專案]顯示建立新空白 C++ 專案的螢幕擷取畫面。

  2. 將新的 C++ 檔案新增至專案。 將檔案的內容變更為:

    import <iostream>;
    import <vector>;
    

設定專案屬性

設定專案屬性以共用此專案的標頭單元:

  1. 在 Visual Studio 主功能表上,選取 [專案]>[SharedPrj 屬性] 以開啟專案 [屬性頁] 對話方塊:顯示 [組態類型] 和 [C++ 語言標準] 設定的螢幕擷取畫面。
  2. 在 [組態] 下拉式清單中選取 [所有組態],然後在 [平台] 下拉式清單中選取 [所有平台]。 這些設定可確保您的變更適用於您要建置以用於偵錯或發行。
  3. 在專案 [屬性頁] 對話方塊的左窗格中,選取 [組態屬性]>[一般]
  4. 將 [組態類型] 選項變更為 [靜態程式庫 (.lib)]
  5. 將 [C++ 語言標準] 變更為 [ISO C++20 標準 (/std:c++20)] (或更新版本)。
  6. 在專案 [屬性頁] 對話方塊的左窗格中,選取 [組態屬性]>[C/C++]>[一般]
  7. 在 [掃描模組相依性的來源] 下拉式清單中,選取 [是]。 (此選項會讓編譯器掃描程式碼中可以內建於標頭單元中的相依性):顯示掃描模組相依性屬性設定的螢幕擷取畫面。
  8. 選擇 [確定] 以關閉專案 [屬性頁] 對話方塊。 選取主功能表上的 [建置]>[建置方案] 以建置方案。

參考標頭單元程式庫

若要從靜態程式庫匯入 <iostream><vector> 作為標頭單元,請建立參考靜態程式庫的專案,如下所示:

  1. 當目前的方案仍然開啟時,在 Visual Studio 功能表上,選取 [檔案]>[新增]>[新專案]

  2. 在 [建立新專案] 精靈中,選取 C++ [主控台應用程式] 範本,然後選擇 [下一步]

  3. 將新專案命名為「逐步解說」。 將 [方案] 下拉式清單變更為 [新增至方案]。 選擇 [建立] 以建立專案,並將其新增至您的方案。

  4. 變更 Walkthrough.cpp 來源檔案的內容,如下所示:

    import <iostream>;
    import <vector>;
    
    int main()
    {
        std::vector<int> numbers = {0, 1, 2};
        std::cout << numbers[1];
    }
    

標頭單元需要 /std:c++20 選項 (或更新版本)。 使用下列步驟設定語言標準:

  1. 在 [方案總管] 中,以滑鼠右鍵按一下 [逐步解說] 專案,然後選取 [屬性] 以開啟專案 [屬性頁] 對話方塊:顯示將語言標準設定為預覽版本的螢幕擷取畫面。
  2. 在 [逐步解說] 專案 [屬性頁] 對話方塊的左窗格中,選取 [組態屬性]>[一般]
  3. 在 [C++ 語言標準] 下拉式清單中,選取 [ISO C++20 標準 (/std:c++20)] (或更新版本)。
  4. 選擇 [確定] 以關閉專案 [屬性頁] 對話方塊。

在 [逐步解說] 專案中,使用下列步驟新增 [SharedPrj] 專案的參考:

  1. 在 [逐步解說] 專案中,選取 [參考] 節點,然後選取 [新增參考]。 在專案清單中選取 [SharedPrj]顯示 [新增參考] 對話方塊的螢幕擷取畫面。它用來新增 [逐步解說] 專案的參考。 新增此參考時,每當 [逐步解說] 專案中的 import 符合 [SharedPrj] 中其中一個建置的標頭單元時,建置系統就會使用 [SharedPrj] 所建置的標頭單元。
  2. 選擇 [確定] 以關閉 [新增參考] 對話方塊。
  3. 以滑鼠右鍵按一下 [逐步解說] 專案,然後選取 [設定為啟始專案]
  4. 建置方案。 (使用主功能表上的 [建置]>[建置方案]。)執行它以檢視其產生預期的輸出:1

這種方法的優點是,您可以從任何專案參考靜態程式庫專案,以重複使用其中的標頭單元。 在此範例中,靜態程式庫包含 <vector><iostream> 標頭單元。

您可以建立整合型靜態程式庫專案,其中包含您想要從各種專案匯入的所有常用 STL 標頭。 或者,您可以針對您想要匯入為標頭單元的不同 STL 程式庫群組,建立較小的共用程式庫專案。 然後視需要參考這些共用標頭單元專案。

結果應該會增加建置輸送量,因為匯入標頭單元會大幅減少編譯器必須執行的工作。

當您將此方法與您自己的專案搭配使用時,請使用與參考它的專案相容的編譯器選項來建置靜態程式庫專案。 例如,應該使用 /EHsc 編譯器選項來建置 STL 專案,以開啟例外狀況處理,因此參考靜態程式庫專案的專案也應該如此。

使用 /translateInclude

/translateInclude 編譯程式選項 (可在 [C/C++]>[一般]>[將 Include 轉譯為 Import] 底下的專案 [屬性頁] 對話方塊中使用),可讓您更輕鬆地在 #include STL 程式庫的舊專案中使用標頭單元程式庫。 它不需要在專案中將 #include 指示詞變更為 import,同時仍可讓您匯入標頭單元,而不是包含它們。

例如,如果您在專案中擁有 #include <vector>,且參考包含 <vector> 標頭單元的靜態程式庫,則不需要在原始程式碼中手動將 #include <vector> 變更為 import <vector>;。 相反地,編譯器會自動將 #include <vector> 視為 import <vector>;。 如需此方法的詳細資訊,請參閱方法 2:針對要匯入的 STL 標頭掃描 Include。 並非所有 STL 標頭檔都可以編譯為標頭單元。 header-units.json 隨附的 Visual Studio 會列出哪些 STL 標頭檔可以編譯成標頭單元。 依賴巨集來指定其行為的標頭,通常無法編譯成標頭單元。

未參考標頭單元的 #include 陳述式會被視為一般 #include

在專案之間重複使用標頭單元

靜態程式庫專案所建置的標頭單元會自動提供給所有直接或間接參考專案。 有專案設定可讓您選取哪些標頭單元應該自動提供給所有參考專案使用。 這些設定位於 [VC++ 目錄] 下的專案設定中。

  1. 在 [方案總管] 中,以滑鼠右鍵按一下專案,並選取 [屬性] 以開啟專案 [屬性頁] 對話方塊。
  2. 在對話方塊的左窗格中,選取 [組態屬性]>[VC++ 目錄]顯示公用專案內容屬性的螢幕擷取畫面,例如公用 Include 目錄和所有標頭檔都是公用的。

下列屬性可控制建置系統的標頭單元可見度:

  • 公用 Include 目錄會指定標頭單元的專案目錄,這些標頭單元應該會自動新增至參考專案中的 Include 路徑。
  • 公用 C++ 模組目錄會指定哪些專案目錄包含應該可供參考專案的標頭單元。 這個屬性可讓您公開某些標頭單元。 其他專案可以看到它,因此請將您想要在這裡共用的標頭單元放在這裡。 如果您使用此設定,為了方便起見,請指定公用 Include 目錄,以自動將公用標頭新增至參考專案中的 Include 路徑。
  • 所有模組都是公用:當您使用建置為 DLL 專案一部分的標頭單元時,符號必須從 DLL 匯出。 若要自動匯出模組符號,請將此屬性設定為 [是]

使用預先建置的模組檔案

一般而言,在方案之間重複使用標頭單元最簡單的方式,就是從每個方案參考共用標頭單元專案。

如果您必須使用沒有專案的建置標頭單元,您可以指定建置 .ifc 檔案的位置,以便將其匯入方案中。 若要存取此設定:

  1. 在主功能表上,選取 [專案]>[屬性] 以開啟專案 [屬性頁] 對話方塊。
  2. 在對話方塊的左窗格中,選取 [組態屬性]>[C/C++]>[一般]
  3. 在 [其他模組相依性] 中,新增要參考的模組,並以分號分隔。 以下是用於其他模組相依性的格式範例:ModuleName1=Path\To\ModuleName1.ifc; ModuleName2=Path\To\ModuleName2.ifc顯示 [組態屬性]、[C/C++]、[一般] 底下專案 [屬性頁] 屬性的螢幕擷取畫面,其中已選取 [其他模組相依性]。

選取標頭單元的多個複本

如果您參考建置多個標頭單元的專案,無論是使用相同名稱或針對相同的標頭檔,您必須指定要使用的項目。 例如,您可能有使用不同編譯器設定所建置的標頭單元版本,且必須指定符合專案設定的標頭單元。

使用專案的 [其他標頭單元相依性] 屬性,藉由指定要使用的標頭單元來解決衝突。 否則,無法預測挑選哪一個。

若要設定 [其他標頭單元相依性] 屬性:

  1. 在主功能表上,選取 [專案]>[屬性] 以開啟專案 [屬性頁] 對話方塊。
  2. 在對話方塊的左窗格中,選取 [組態屬性]>[C/C++]>[一般]
  3. 指定要用於 [其他標頭單元相依性] 的模組或標頭單元檔案,以解決衝突。 針對 [其他標頭單元相依性] 使用此格式:Path\To\Header1.h= Path\To\HeaderUnit1.ifc;Path\To\Header2.h= Path\To\ HeaderUnit2.ifc顯示專案 [屬性頁] 對話方塊中 [其他標頭單元相依性] 設定的螢幕擷取畫面。

重要

請確定共用標頭單元的專案是使用相容的編譯選項所建置。 如果您在實作與建立標頭單元不同的標頭單元時使用編譯選項,編譯器將會發出警告。

注意

若要使用作為 DLL 專案的一部分建置的標頭單元,請將 [所有模組] 設為 [是]

方法 2:針對要匯入的 STL 標頭掃描 Include

另一個匯入 STL 程式庫的方式是讓 Visual Studio 掃描您在專案中 #include 的 STL 標頭,並將其編譯為標頭單元。 編譯器接著會匯入,而不是包含這些標頭。

當您的專案包含許多檔案的 STL 標頭檔,或建置輸送量並不重要時,此選項就很方便。 此選項並不保證針對特定標頭檔的標頭單元只會建置一次。 不過,如果您有大型程式碼基底,就很有用:您不需要變更原始程式碼,就能利用您所使用許多 STL 程式庫的標頭單元優點。

這種方法比靜態程式庫方法更不具彈性,因為它本身無法重複使用其他專案中的建置標頭單元。 此方法可能不適用於較大的專案:它並不保證最佳的建置時間,因為所有來源都必須掃描 #include 陳述式。

並非所有標頭檔都可以自動轉換成標頭單元。 例如,相依於透過巨集進行條件式編譯的標頭不應該轉換成標頭單元。 允許清單的格式為編譯器在指定 /translateInclude 時所使用 STL 標頭的 header-units.json 檔案。 它會決定哪些 STL 標頭可以編譯成標頭單元。 header-units.json 檔案位於 Visual Studio 的安裝目錄底下。 例如: %ProgramFiles%\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.30.30705\include\header-units.json 。 如果 STL 標頭檔不在清單中,則會將其視為一般 #include,而不是將其匯入為標頭單元。 header-units.json 檔案的另一個優點是,它會防止內建標頭單元中的符號重複。 也就是說,如果編譯標頭單元多次帶入另一個程式庫標頭,則不會複製符號。

若要試用此方法,請建立包含兩個 STL 程式庫的專案。 然後,變更專案的屬性,使其將程式庫匯入為標頭單元,而不是包含它們,如下一節所述。

建立 C++ 主控台應用程式專案

請遵循下列步驟來建立包含兩個 STL 程式庫的專案:<iostream><vector>

  1. 在 Visual Studio 中,建立新的 C++ 主控台應用程式專案。

  2. 取代來源檔案的內容,如下所示:

    #include <iostream>;
    #include <vector>;
    
    int main()
    {
        std::vector<int> numbers = {0, 1, 2};
        std::cout << numbers[1];
    }
    

設定專案選項並執行專案

下列步驟會設定選項,讓編譯器掃描包含的標頭,以轉譯成標頭單元。 它們也會設定選項,讓編譯器將 #include 視為您已針對可視為標頭單元的標頭檔撰寫 import

  1. 在主功能表上,選取 [專案]>[屬性] 以開啟專案 [屬性頁] 對話方塊。
  2. 在 [組態] 下拉式清單中選取 [所有組態],然後在 [平台] 下拉式清單中選取 [所有平台]。 這些設定可確保您的變更適用於您要建置以用於偵錯或發行,以及其他組態。
  3. 在對話方塊的左窗格中,選取 [組態屬性]>[C/C++]>[一般]
  4. 將 [掃描來源是否具有模組相依性] 設為 [是]。 此設定可確保所有相容的標頭檔都會編譯為標頭單元。
  5. 將 [將 Include 轉譯為 Import] 設為 [是]。 此設定會將 header-unit.json 檔案中列出的 STL 標頭檔編譯為標頭單元,然後匯入它們,而不是使用前置處理器將其 #include顯示專案 [屬性頁] 中掃描模組相依性屬性設定的螢幕擷取畫面。
  6. 選擇 [確定] 以儲存您的變更,然後關閉專案 [屬性頁] 對話方塊。

使用標頭單元需要 /std:c++20 選項或更新版本。 若要變更編譯器所使用的 C++ 語言標準:

  1. 在主功能表上,選取 [專案]>[屬性] 以開啟專案 [屬性頁] 對話方塊。
  2. 在 [組態] 下拉式清單中選取 [所有組態],然後在 [平台] 下拉式清單中選取 [所有平台]。 這些設定可確保您的變更適用於您要建置以用於偵錯或發行,以及其他組態。
  3. 在專案 [屬性頁] 對話方塊的左窗格中,選取 [組態屬性]>[一般]
  4. 在 [C++ 語言標準] 下拉式清單中,選取 [ISO C++20 標準 (/std:c++20)] (或更新版本)。
  5. 選擇 [確定] 以儲存您的變更,然後關閉專案 [屬性頁] 對話方塊。
  6. 從主功能表中,選取 [建置]>[建置方案] 以建置方案。

執行方案以確認其產生預期的輸出:1

是否使用此方法的主要考量是便利性與掃描所有檔案成本之間的衡,以判斷要建置為標頭單元的標頭檔。

另請參閱

比較標頭單位、模組和先行編譯標頭檔
教學課程:使用模組匯入 C++ 標準程式庫
逐步解說:在您的 Visual C++ 專案中建置和匯入標頭單元
/translateInclude