42

私は、 C++ の提案された機能である C++ モジュールを理解するために、論文A Module System for C++を読んでいます。

このモジュール アーキテクチャによってテンプレートがどのようにエクスポートされるのか、完全には理解できません。

何か案は?

4

1 に答える 1

43

現在、C++ の実装には、実際にはコードに対応する 2 つの「もの」しかありません。それは、人間が作成および編集するソース コードと、ソースに基づいてコンパイラが吐き出すアセンブリです。

C++ テンプレートは「具体化」されているため、テンプレートのインスタンス化ごとに個別のアセンブリが吐き出されます。そのため、テンプレートが定義されている場所ではアセンブリを作成できず、テンプレートが使用されている場所でのみ作成できます。これが、テンプレートをヘッダー ファイルに配置して、基本的に使用箇所にコピー ペーストできるようにする必要がある理由です (#include はこれだけです)。

アイデアは、コードの 3 番目の表現を持つことです。コンパイラがコードを解析した、アセンブリの生成を開始するに、コンパイラが内部的に何らかの内部表現を持っていると想像してください。それが生成する「もの」は、最終的には抽象構文木 (AST) のある種の表現です。基本的には、人間にとって最も簡単な形式からコンピューターにとって最も簡単な形式にマップされた、まさにあなたのプログラムです。

これは、モジュール (または少なくともその実装) の背後にある非常に大まかな考え方です。コードを取り出して、AST を表すある種のファイルを吐き出します。この AST はプログラムの完全な表現であるため、完全にロスレスです。宣言したテンプレートなどについてすべて知っています。モジュールがロードされると、このファイルがロードされるだけで、コンパイラはすべてのソースが利用可能であるかのようにそれを使用できます。しかし、人間が読めるソースをこの AST に変換するステップは、実際には非常にコストのかかるステップです。AST から開始すると、はるかに高速になります。

翻訳単位が 1 つしかない場合、これは遅くなります。結局のところ、解析 -> codegen は、解析 -> シリアライズ -> デシリアライズ -> codegen よりも依然として高速です。しかし、すべて #include ベクターの翻訳単位が 10 個あるとします。ベクトルのコードを 10 回解析します。この時点で、シリアル化/逆シリアル化の余分なコストは、解析が 1 回だけで済むという事実によって相殺されます (逆シリアル化は解析よりもはるかに高速に実行できます。このデータ形式は、逆シリアル化を高速化するために特別に設計されていますが、ソース コードは可読性、下位互換性などを考慮して設計されています)。

コンパイル済みヘッダーは、ある意味でモジュールのスニーク プレビューです: https://clang.llvm.org/docs/PCHInternals.html

于 2017-05-09T07:38:05.417 に答える