web-dev-qa-db-ja.com

テンプレートはC ++モジュールシステムでどのように処理されますか?

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

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

何か案は?

32
Monku

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

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

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

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

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

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

25
Nir Friedman