モジュール インターフェイス ユニットとモジュール実装ユニットのおかげで、モジュールを定義するときにインターフェイスを実装から分離できます。その方法をお見せしましょう。
前回の投稿 C++20:A Simple math Modul で約束したように、私の Clang Odyssee について少し寄り道したいと思います。私の回り道は、参照された投稿で私が書いたすべてのコンパクトな復習です.
マイ クラン オデッセイ
まず、私以外の誰かを責めたくありません。 CppCon 2017 での Boris Kolpackov の「Building C++ Modules」または Corentin Jabot の「モジュールはツールの機会ではない」という講演に基づいて、ベンダーはモジュール定義に次の拡張機能を提案しているという印象を受けました。
- Windows:ixx
- Clang:cppm
- GCC:提案なし
Clang コンパイラの場合、私は完全に間違っていました。これは私の単純な数学モジュールで、Clang コンパイラでコンパイルしようとしました。
// math.cppm export module math; export int add(int fir, int sec){ return fir + sec; }
Microsoft と Linux で Clang 9 と Clang 10 を使用してモジュールをコンパイルしようとしました。ソースからビルドされた最新の Clang 11 コンパイラでコンパイルしようとしました。これが私の多くの試みの1つです。
このコマンドラインは、モジュール math.pcm を作成する必要があります。コマンドラインで指定した -std=c++20 -fmodules-ts エラーメッセージは次のように述べています:モジュールインターフェイスのコンパイルには「-std =c ++ 20」または「-fmodules-ts」が必要です . 2 つのフラグのすべてのバリエーションを作成し、グローバル モジュール フラグメントをモジュール定義に追加し、追加のフラグで Clang コンパイラを呼び出しましたが、結果は常に同じでした。
それから、アーサー・オドワイヤーとローランド・ボックに助けを求めました。 Arthur モジュールの場合、Clang で問題なく動作しました:「Hello World with C++2a modules」。 Roland は Clang 11 を再構築し、私のモジュール定義で動作しました。
Roland と私は文字通り、同じ Clang コンパイラと同じモジュール定義を持っていました。キャラクターごとに、彼のコマンドラインと私のコマンドラインを比較したところ、何かに気づきました.
Mine: clang++ -std=c++20 - -fmodules-ts -stdlib=libc++ -c math.cppm -Xclang -emit-module-interface -o math.pcm Roland: clang++ -std=c++20 - -fmodules-ts -stdlib=libc++ -c math.cpp -Xclang -emit-module-interface -o math.pcm
Roland は彼のモジュールに math.cpp cpp を与え、Arthur もそうしました。モジュール定義に接尾辞 cppm を与えないでください .
これで、モジュールのコンパイルと使用は簡単になりました。
このオデッセイを締めくくるには、ここに client.cpp ファイルと、Clang コマンド ラインに必要なフラグをいくつか示します。
// client.cpp import math; int main() { add(2000, 20); }
clang++ -std=c++2a -stdlib=libc++ -c math.cpp -Xclang -emit-module-interface -o math.pcm // (1) clang++ -std=c++2a -stdlib=libc++ -fprebuilt-module-path=. client.cpp math.pcm -o client // (2)
<オール>
モジュールの計算は簡単でした。もう少し洗練してみましょう。
モジュール構造のガイドライン
モジュール構造の最初のガイドラインは次のとおりです:
module; // global module fragment #include <headers for libraries not modularized so far> export module math; // module declartion import <importing of other modules> <non-exported declarations> // names with only visibiliy inside the module export namespace math { <exported declarations> // exported names }
このガイドラインには 2 つの目的があります。これにより、モジュールの単純化された構造と、これから書く内容についてのアイデアが得られます。では、このモジュール構造の新機能は何ですか?
- モジュールをインポートできます。インポートされたモジュールにはモジュール リンケージがあり、モジュールの外では見えません。この観察は、非輸出申告にも適用されます。
- エクスポートされた名前を、モジュールなどの同じ名前を持つ名前空間 math に入れます。
- モジュールには宣言された名前しかありません。インターフェイスの分離とモジュールの実装について書きましょう。
モジュール インターフェイス ユニット、およびモジュール実装ユニット
前述のガイドラインに従って、前回の投稿 C++20:A Simple math Modul のモジュール math の最終バージョンをリファクタリングしたいと思います。
モジュール インターフェース ユニット
// mathInterfaceUnit.ixx module; import std.core; export module math; export namespace math { int add(int fir, int sec); int getProduct(const std::vector<int>& vec); }
- モジュール インターフェイス ユニットには、エクスポート モジュール宣言が含まれています:export module math.
- add と getProduct という名前がエクスポートされます。
- モジュールは、モジュール インターフェース ユニットを 1 つだけ持つことができます。
モジュール実装ユニット
// mathImplementationUnit.cpp module math; import std.core; int add(int fir, int sec){ return fir + sec; } int getProduct(const std::vector<int>& vec) { return std::accumulate(vec.begin(), vec.end(), 1, std::multiplies<int>()); }
- モジュール実装ユニットには、非エクスポート モジュール宣言が含まれています:module math;
- モジュールには、複数のモジュール実装ユニットを含めることができます。
メイン プログラム
// client3.cpp import std.core; import math; int main() { std::cout << std::endl; std::cout << "math::add(2000, 20): " << math::add(2000, 20) << std::endl; std::vector<int> myVec{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; std::cout << "math::getProduct(myVec): " << math::getProduct(myVec) << std::endl; std::cout << std::endl; }
- ユーザーの観点からは、名前空間の計算のみが追加されました。
実行可能ファイルのビルド
実行可能ファイルを手動でビルドするには、いくつかの手順が含まれます。
cl.exe /std:c++latest /c /experimental:module mathInterfaceUnit.ixx /EHsc /MD // (1) cl.exe /std:c++latest /c /experimental:module mathImplementationUnit.cpp /EHsc /MD // (2) cl.exe /std:c++latest /c /experimental:module client3.cpp /EHsc /MD // (3) cl.exe client3.obj mathInterfaceUnit.obj mathImplementationUnit.obj // (4)
<オール>
Microsoft コンパイラの場合、例外処理モデル (/EHsc) とマルチスレッド ライブラリ (/MD) を指定する必要があります。さらに、フラグ /std:c++latest を使用してください。
最後に、プログラムの出力は次のとおりです。
次は?
次の投稿では、モジュールの数学を新しい機能で拡張します。まず、モジュールをインポートして 1 つのユニットにエクスポートします。次に、モジュール内でのみ表示される名前を使用します。