チュートリアル: STL ライブラリをヘッダ ーユニットとしてインポートする
このチュートリアルでは、Visual Studio で C++ 標準テンプレート ライブラリ (STL) のライブラリをヘッダー ユニットとしてインポートする方法を示します。 さらに速く確実に標準ライブラリをインポートする方法については、モジュールを使用した C++ 標準ライブラリのインポートのチュートリアルに関する記事をご覧ください。
ヘッダー ユニットとしての STL ヘッダーのインポートは、プリコンパイル済みヘッダー ファイルを使うより簡単です。 ヘッダー ユニットは、共有 PCH より、設定と使用がさらに簡単で、ディスク上のサイズがかなり小さく、パフォーマンス上の利点は同等で、いっそう柔軟です。
ヘッダー ユニットの概要とその利点について詳しくは、「ヘッダー ユニットとは」をご覧ください。 ヘッダー ユニットと、標準ライブラリをインポートする他の方法との比較については、「ヘッダー ユニット、モジュール、プリコンパイル済みヘッダーを比較する」をご覧ください。
前提条件
ヘッダー ユニットを使うには、Visual Studio 2022 以降、または Visual Studio 2019 バージョン 16.11 以降を使います。 ヘッダー ユニットを使うには、/std:c++20
オプション (それ以降) が必要です。
ヘッダーユニットとして STL ヘッダーをインポートする 2 つの方法
STL ヘッダーの場合は、インポートする前に、ヘッダー ユニットにコンパイルする必要があります。 ヘッダー ユニットは、ヘッダー ファイルのバイナリ表現です。 .ifc
拡張子を持ちます。
使用する STL ヘッダーのビルド済みヘッダー ユニットを含むスタティック ライブラリを作成する方法をお勧めします。 その後、そのライブラリを参照し、そのヘッダー ユニットに対して import
を使用します。 この方法を使うと、ビルドが速くなり、再利用が容易になる可能性があります。 この方法を試す場合は、「方法 1: STL ライブラリ ヘッダー ユニットのスタティック ライブラリを作成する」を参照してください。
もう 1 つの方法は、Visual Studio を使い、プロジェクトで #include
を使用した STL ヘッダーをスキャンし、ヘッダー ユニットにコンパイルし、それらのヘッダーに対して #include
ではなく、import
を使用することです。 この方法は、ソース コードを変更する必要がないため、大きなコードベースがある場合に便利です。 この方法は、他のプロジェクトのビルド済みヘッダー ユニットの再利用には適していないため、スタティック ライブラリの方法よりも柔軟性が低くなります。 ただし、その場合でも、個々の STL ライブラリをヘッダー ユニットとしてインポートすると、パフォーマンス上の利点は得られます。 この方法を試す場合は、「方法 2: インポートする STL ヘッダーについて include をスキャンする」を参照してください。
方法 1: STL ライブラリ ヘッダー ユニットのスタティック ライブラリを作成する
STL ライブラリをヘッダー ユニットとして使う場合に推奨される方法は、1 つまたは複数のスタティック ライブラリ プロジェクトを作成することです。 これらのプロジェクトは、使用する STL ライブラリ ヘッダー ユニットで構成されている必要があります。 その後、ライブラリ プロジェクトを参照して、それらの STL ヘッダー ユニットを使います。 これは、共有プリコンパイル済みヘッダーを使用するのと似ていますが、それより簡単です。
スタティック ライブラリ プロジェクトでビルドされたヘッダー ユニット (およびモジュール) は、参照元のプロジェクトで自動的に使用できるようになります。これは、参照元のプロジェクトがヘッダー ユニットをインポートできるように、プロジェクト システムによって適切な /headerUnit
コマンドライン オプションがコンパイラに自動的に追加されるためです。
この方法では確実に、特定のヘッダーのヘッダー ユニットが 1 回だけビルドされます。 これにより、ヘッダー ユニットの一部またはすべてをインポートできます (PCH ではできません)。 ヘッダー ユニットは任意の順序で含めることができます。
次の例では、<iostream>
および <vector>
ヘッダー ユニットで構成されるスタティック ライブラリ プロジェクトを作成します。 ソリューションがビルドされると、この共有ヘッダー ユニット プロジェクトを別の C++ プロジェクトから参照します。 import <iostream>;
または import <vector>;
が検出されたすべての場所で、ヘッダーをプリプロセッサで変換するのではなく、そのライブラリのビルド済みヘッダー ユニットが使用されます。 これにより、同じヘッダーが複数のファイルに含まれていると、PCH ファイルの場合のように、ビルドのパフォーマンスが向上します。 ヘッダーで、それが含まれるファイルによって何度も処理される必要がなくなります。 代わりに、既に処理されているコンパイル済みヘッダー ユニットがインポートされます。
STL ライブラリ <iostream>
と <vector>
を含むスタティック ライブラリを作成するには、これらの手順に従います。
空の C++ プロジェクトを作成します。 それに SharedPrj という名前を付けます。
[新しいプロジェクトの作成] ウィンドウで、使用可能なプロジェクトの種類から C++ の [空のプロジェクト] を選びます。新しい C++ ファイルをプロジェクトに追加します。 ファイルの内容を次のように変更します。
import <iostream>; import <vector>;
プロジェクト プロパティを設定する
このプロジェクトからヘッダー ユニットを共有するように、プロジェクトのプロパティを設定します。
- Visual Studio のメイン メニューで [プロジェクト]>[SharedPrj プロパティ] を選んで、プロジェクトの [プロパティ ページ] ダイアログ ボックスを開きます。
- [構成] ドロップダウン リストで [すべての構成] を選んでから、[プラットフォーム] ドロップダウン リストで [すべてのプラットフォーム] を選びます。 これらの設定により、デバッグ用またはリリース用のどちらをビルドしていても、変更が確実に適用されます。
- プロジェクトの [プロパティ ページ] ダイアログの左ペインで、[構成プロパティ]>[全般] を選びます。
- [構成の種類] オプションを [スタティック ライブラリ (.lib)] に変更します。
- [C++ 言語標準] を ISO C++20 標準 (/std:c++20) (以降) に変更します。
- プロジェクトの [プロパティ ページ] ダイアログの左ペインで、[構成プロパティ]>[C/C++]>[全般] を選びます。
- [モジュール依存関係のソースをスキャンする] ドロップダウン リストで、[はい] を選びます。 (このオプションを選ぶと、コンパイラは、ヘッダー ユニットにビルドできる依存関係をコードでスキャンします)。
- [OK] を選んで、プロジェクトの [プロパティ ページ] ダイアログを閉じます。 メイン メニューの [ビルド]>[ソリューションのビルド] を選択して、ソリューションをビルドします。
ヘッダー ユニット ライブラリを参照する
<iostream>
と <vector>
をスタティック ライブラリからヘッダー ユニットとしてインポートするには、次のようにスタティック ライブラリを参照するプロジェクトを作成します。
現在のソリューションを開いたまま、Visual Studio のメニューで、[ファイル]>[追加]>[新しいプロジェクト] を選択します。
[新しいプロジェクトの作成] ウィザードで、C++ の [コンソール アプリ] テンプレートを選んで、[次へ] を選びます。
新しいプロジェクトに Walkthrough という名前を付けます。 [ソリューション] ドロップダウンを [ソリューションに追加] に変更します。 [作成] を選んでプロジェクトを作成し、それをソリューションに追加します。
Walkthrough.cpp ソース ファイルの内容を次のように変更します。
import <iostream>; import <vector>; int main() { std::vector<int> numbers = {0, 1, 2}; std::cout << numbers[1]; }
ヘッダー ユニットには、/std:c++20
オプション (それ以降) が必要です。 以下の手順を使用して、言語標準を設定します。
- ソリューション エクスプローラーで Walkthrough プロジェクトを右クリックし、[プロパティ] を選んでプロジェクトの [プロパティ ページ] ダイアログを開きます。
- Walkthrough プロジェクトの [プロパティ ページ] ダイアログの左ペインで、[構成プロパティ]>[全般] を選びます。
- [C++ 言語標準] ドロップダウンで、ISO C++20 標準 (/std:c++20) (以降) を選びます。
- [OK] を選んで、プロジェクトの [プロパティ ページ] ダイアログを閉じます。
Walkthrough プロジェクトで、次の手順で SharedPrj プロジェクトへの参照を追加します。
- Walkthrough プロジェクトで [参照] ノードを選択し、[参照の追加] を選択します。 プロジェクトの一覧で SharedPrj を選択します。 この参照を追加すると、ビルド システムは、Walkthrough プロジェクトの
import
が SharedPrj 内のいずれかのビルド済みヘッダー ユニットと一致するたびに、SharedPrj によってビルドされたヘッダー ユニットを使うようになります。 - [OK] を選んで、[参照の追加] ダイアログを閉じます。
- Walkthrough プロジェクトを右クリックし、[スタートアップ プロジェクトに設定] を選択します。
- ソリューションをビルドします。 (メイン メニューの [ビルド]>[ソリューションのビルド] を使います)。これを実行して、予想される出力 (
1
) が生成されることを確認します。
この方法の利点は、任意のプロジェクトからスタティック ライブラリ プロジェクトを参照して、ヘッダー ユニットを再利用できることです。 この例では、スタティック ライブラリに <vector>
および <iostream>
ヘッダー ユニットが含まれています。
さまざまなプロジェクトからインポートする、一般的に使用されるすべての STL ヘッダーを含めたモノリシックなスタティック ライブラリ プロジェクトを作成できます。 または、ヘッダー ユニットとしてインポートする STL ライブラリの異なるグループ用に、より小さな共有ライブラリ プロジェクトを作成することもできます。 その後、必要に応じて、それらの共有ヘッダー ユニット プロジェクトを参照します。
結果として、ヘッダー ユニットをインポートすると、コンパイラで行う必要のある作業が大幅に減るため、ビルドのスループットが向上します。
この方法をご自分のプロジェクトで使用する場合は、それを参照するプロジェクトと互換性のあるコンパイラ オプションを使って、スタティック ライブラリ プロジェクトをビルドします。 たとえば、STL プロジェクトは例外処理を有効にするために /EHsc
コンパイラ オプションを使用してビルドする必要があるため、スタティック ライブラリ プロジェクトを参照するプロジェクトでもそれが必要になります。
/translateInclude
を使用します
/translateInclude
コンパイラ オプション (プロジェクトの [プロパティ ページ] ダイアログの [C/C++]>[全般]>[インクルードをインポートに変換する] にあります) を使うと、STL ライブラリに対して #include
を使用する以前のプロジェクトで、ヘッダー ユニット ライブラリをより簡単に使用できるようになります。 プロジェクト内の #include
ディレクティブを import
に変更する必要はなくなりますが、ヘッダー ユニットを含めるのではなく、インポートするという利点は引き続き得られます。
たとえば、プロジェクトに #include <vector>
があり、<vector>
用のヘッダー ユニットが含まれるスタティック ライブラリを参照する場合、手動でソース コードの #include <vector>
を import <vector>;
に変更する必要はありません。 代わりに、コンパイラは #include <vector>
を import <vector>;
として自動的に処理します。 この方法について詳しくは、「方法 2: インポートする STL ヘッダーについて include をスキャンする」をご覧ください。 すべての STL ヘッダー ファイルをヘッダー ユニットにコンパイルできるわけではありません。 Visual Studio に付属の header-units.json
には、ヘッダー ユニットにコンパイルできる STL ヘッダー ファイルが一覧表示されています。 その動作を指定するためにマクロに依存するヘッダーは、多くの場合、ヘッダー ユニットにコンパイルできません。
ヘッダー ユニットを参照しない #include
ステートメントは、通常の #include
として扱われます。
プロジェクト間でヘッダー ユニットを再利用する
スタティック ライブラリ プロジェクトによってビルドされたヘッダー ユニットは、直接的または間接的に参照しているすべてのプロジェクトで自動的に使用できるようになります。 参照しているすべてのプロジェクトで自動的に使用できるようにする必要があるヘッダー ユニットを選択できプロジェクト設定があります。 この設定は、プロジェクトの設定の [VC++ ディレクトリ] にあります。
- ソリューション エクスプローラーでプロジェクトを右クリックし、[プロパティ] を選んでプロジェクトの [プロパティ ページ] ダイアログを開きます。
- ダイアログの左側のペインで、[構成プロパティ]>[VC++ ディレクトリ] を選びます。
次のプロパティは、ビルド システムに対するヘッダー ユニットの可視性を制御します。
- [パブリック インクルード ディレクトリ] では、参照元プロジェクトのインクルード パスに自動的に追加する必要があるヘッダー ユニット用プロジェクト ディレクトリを指定します。
- [パブリック C++ モジュール ディレクトリ] では、参照元プロジェクトで使用できるようにする必要があるヘッダー ユニットが含まれるプロジェクト ディレクトリを指定します。 このプロパティを使うと、一部のヘッダー ユニットをパブリックにできます。 他のプロジェクトで認識できるようになるので、共有したいヘッダー ユニットはここに置きます。 この設定を使う場合は、便宜のため、[パブリック インクルード ディレクトリ] を指定して、パブリック ヘッダーを参照元プロジェクトのインクルード パスに自動的に追加します。
- すべてのモジュールがパブリックである: DLL プロジェクトの一部としてビルドされたヘッダー ユニットを使用する場合は、シンボルを DLL からエクスポートする必要があります。 モジュールのシンボルを自動的にエクスポートするには、このプロパティを [はい] に設定します。
ビルド済みのモジュール ファイルを使用する
通常、ソリューション間でヘッダー ユニットを再利用する最も簡単な方法は、各ソリューションから共有ヘッダー ユニット プロジェクトを参照することです。
プロジェクトがないビルド済みヘッダー ユニットを使用する必要がある場合は、ソリューションにインポートできるように、ビルド済みの .ifc
ファイルの場所を指定できます。 この設定にアクセスするには:
- メイン メニューから [プロジェクト]>[プロパティ] を選んで、プロジェクトの [プロパティ ページ] ダイアログを開きます。
- ダイアログの左側のペインで、[構成プロパティ]>[C/C++]>[全般] を選びます。
- [追加のモジュールの依存関係] で、参照するモジュールをセミコロンで区切って追加します。 [追加のモジュールの依存関係] で使う形式の例を次に示します:
ModuleName1=Path\To\ModuleName1.ifc; ModuleName2=Path\To\ModuleName2.ifc
ヘッダー ユニットの複数のコピーから選択する
同じ名前または同じヘッダー ファイルで複数のヘッダー ユニットがビルドされるプロジェクトを参照する場合は、使用するものを指定する必要があります。 たとえば、ヘッダー ユニットの複数の異なるバージョンが異なるコンパイラ設定でビルドされる場合は、プロジェクトの設定と一致するものを指定する必要があります。
使うヘッダー ユニットを指定して競合を解決するには、プロジェクトの [追加のヘッダー ユニットの依存関係] プロパティを使います。 そうしないと、どれが選択されるかを予測できません。
[追加のヘッダー ユニットの依存関係] プロパティを設定するには:
- メイン メニューから [プロジェクト]>[プロパティ] を選んで、プロジェクトの [プロパティ ページ] ダイアログを開きます。
- ダイアログの左側のペインで、[構成プロパティ]>[C/C++]>[全般] を選びます。
- 競合を解決するには、[追加のヘッダー ユニットの依存関係] で使うモジュールまたはヘッダー ユニット ファイルを指定します。 [追加のヘッダー ユニットの依存関係] では、次の形式を使います:
Path\To\Header1.h= Path\To\HeaderUnit1.ifc;Path\To\Header2.h= Path\To\ HeaderUnit2.ifc
重要
ヘッダー ユニットを共有するプロジェクトが、互換性のあるコンパイル オプションを使用してビルドされていることを確認します。 作成時に使用したものとは異なるヘッダー ユニットを実装するときにコンパイル オプションを使用すると、コンパイラから警告が発行されます。
Note
DLL プロジェクトの一部として組み込まれているヘッダー ユニットを使用するには、[All Modules are Public]\(すべてのモジュールがパブリック\) を [はい] に設定します。
方法 2: インポートする STL ヘッダーについて include をスキャンする
STL ライブラリをインポートするもう 1 つの方法は、Visual Studio を使い、プロジェクトで #include
を使用した STL ヘッダーをスキャンし、ヘッダー ユニットにコンパイルすることです。 その後、コンパイラによって、これらのヘッダーが含まれるのではなく、インポートされます。
このオプションは、プロジェクトに多くのファイルにわたって多くの STL ヘッダー ファイルが含まれる場合や、ビルド スループットが重要ではない場合に便利です。 このオプションでは、特定のヘッダー ファイルのヘッダー ユニットが 1 回だけビルドされることは保証されません。 ただし、大きいコードベースがある場合は便利です。使用する STL ライブラリの多くでヘッダー ユニットの利点を活用するために、ソース コードを変更する必要がありません。
この方法は、他のプロジェクトでビルドされたヘッダー ユニットの再利用には適していないため、スタティック ライブラリの方法より柔軟性は低くなります。 すべてのソースで #include
ステートメントをスキャンする必要があるので、最善のビルド時間が保証されないため、この方法は大きなプロジェクトには適していない可能性があります。
すべてのヘッダー ファイルをヘッダー ユニットに自動的に変換できるわけではありません。 たとえば、マクロを使用した条件付きコンパイルに依存するヘッダーは、ヘッダー ユニットに変換できません。 STL ヘッダーには、/translateInclude
を指定するとコンパイラによって使われる、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
ファイルのもう 1 つの利点は、ビルド済みヘッダー ユニットでのシンボルの重複を防ぐことです。 つまり、ヘッダー ユニットをコンパイルすると、別のライブラリ ヘッダーが複数回取り込まれても、シンボルは重複しません。
この方法を試すには、2 つの STL ライブラリを含むプロジェクトを作成します。 その後、次のセクションで説明するように、ライブラリをインクルードするのではなく、ヘッダー ユニットとしてインポートするように、プロジェクトのプロパティを変更します。
C++ コンソール アプリ プロジェクトを作成する
これらの手順に従って、<iostream>
と <vector>
の 2 つの STL ライブラリを含むプロジェクトを作成します。
Visual Studio で、新しい C++ コンソール アプリ プロジェクトを作成します。
ソース ファイルの内容を次のように置き換えます。
#include <iostream>; #include <vector>; int main() { std::vector<int> numbers = {0, 1, 2}; std::cout << numbers[1]; }
プロジェクトのオプションを設定してプロジェクトを実行する
次の手順では、含まれているヘッダーをコンパイラでスキャンし、ヘッダー ユニットに変換するようにオプションを設定します。 また、ヘッダー ユニットとして扱えるヘッダー ファイルに対して import
を記述した場合と同様に、コンパイラで #include
を扱うようにするオプションも設定します。
- メイン メニューから [プロジェクト]>[プロパティ] を選んで、プロジェクトの [プロパティ ページ] ダイアログを開きます。
- [構成] ドロップダウン リストで [すべての構成] を選んでから、[プラットフォーム] ドロップダウン リストで [すべてのプラットフォーム] を選びます。 これらの設定により、デバッグ用またはリリース用、および他の構成をビルドしているかどうかにかかわらず、変更が確実に適用されます。
- ダイアログの左側のペインで、[構成プロパティ]>[C/C++]>[全般] を選びます。
- [モジュール依存関係のソースをスキャンする] を [はい] に設定します。 この設定により、互換性のあるすべてのヘッダー ファイルがヘッダー ユニットとして確実にコンパイルされます。
- [インクルードをインポートに変換する] を [はい] に設定します。 この設定では、
header-unit.json
ファイルにリストされている STL ヘッダー ファイルがヘッダー ユニットとしてコンパイルされた後、プリプロセッサを使って#include
が行われるのではなく、インポートされます。 - [OK] を選んで変更を保存し、プロジェクトの [プロパティ ページ] ダイアログを閉じます。
ヘッダー ユニットを使うには、/std:c++20
オプション以降が必要です。 コンパイラによって使われる C++ 言語標準を変更するには:
- メイン メニューから [プロジェクト]>[プロパティ] を選んで、プロジェクトの [プロパティ ページ] ダイアログを開きます。
- [構成] ドロップダウン リストで [すべての構成] を選んでから、[プラットフォーム] ドロップダウン リストで [すべてのプラットフォーム] を選びます。 これらの設定により、デバッグ用またはリリース用、および他の構成をビルドしているかどうかにかかわらず、変更が確実に適用されます。
- プロジェクトの [プロパティ ページ] ダイアログの左ペインで、[構成プロパティ]>[全般] を選びます。
- [C++ 言語標準] ドロップダウン リストで、ISO C++20 標準 (/std:c++20) (以降) を選びます。
- [OK] を選んで変更を保存し、プロジェクトの [プロパティ ページ] ダイアログを閉じます。
- メイン メニューから [ビルド]>[ソリューションのビルド] の順に選択して、ソリューションをビルドします。
ソリューションを実行して、予想される出力 1
が生成されることを確認します。
この方法を使用するかどうかの主な考慮事項は、利便性と、ヘッダー ユニットとしてビルドするヘッダー ファイルを決定するためにすべてのファイルをスキャンするコストの間のバランスを取ることです。
関連項目
ヘッダー ユニット、モジュール、プリコンパイル済みヘッダーを比較する
チュートリアル: モジュールを使用して C++ 標準ライブラリ (STL) をインポートする
チュートリアル: Visual C++ プロジェクトでヘッダー ユニットをビルドしてインポートする
/translateInclude