web-dev-qa-db-ja.com

C ++ 20モジュールでテンプレートの明示的なインスタンス化を使用するにはどうすればよいですか?

説明したように この回答で テンプレートのインスタンス化により、テンプレートを使用するすべての新しいファイルのすべての新しいタイプについてテンプレートを再コンパイルする必要がないため、コンパイル時間とサイズを削減できます。

C++ 20モジュール がテンプレートを外部プロジェクトに公開し、hpp/cppの重複を削減するためのクリーンなソリューションを提供する方法にも興奮しています。

彼らが一緒に働くことを可能にする構文は何ですか?

たとえば、モジュールが少し似ていることを期待します(テストされていないため、コードが間違っている可能性があります。コンパイラが十分に新しいわけではない/まだ実装されていないためです)。

helloworld.cpp

export module helloworld;
import <iostream>;

template<class T>
export void hello(T t) {
    std::cout << t << std::end;
}

helloworld_impl.cpp

export module helloworld_impl;
import helloworld;

// Explicit instantiation
template class hello<int>;

main.cpp

// How to prevent the full definition from being imported here, which would lead
// hello(1) to instantiate a new `hello<int>` instead of reusing the explicit instantiated
// one from `helloworld_impl.cpp`?
import helloworld;

int main() {
    hello(1);
}

https://quuxplusone.github.io/blog/2019/11/07/modular-hello-world で言及されているコンパイルは(?)

clang++ -std=c++2a -c helloworld.cpp -Xclang -emit-module-interface -o helloworld.pcm
clang++ -std=c++2a -c -fprebuilt-module-path=. -o helloworld_impl.o helloworld_impl.cpp
clang++ -std=c++2a -fprebuilt-module-path=. -o main.out main.cpp helloworld_impl.o

理想的には、テンプレート定義を外部プロジェクトでも使用できるようにしたいと考えています。

私が欲しいのはモジュールをインポートする方法だと思います、そしてインポート時にどちらかを決定します:

  • それらが宣言のみであるかのように、モジュール内のすべてのテンプレートを使用します(別のファイルで独自のインスタンス化を提供します)
  • モジュール内のテンプレートを定義のように使用します

これは基本的に、C++ 20より前の "定義をインクルードされたヘッダーから削除するだけでなく、テンプレートに外部APIを公開する"で実現します しかし、その設定では、インターフェイスを2回コピーする必要があります。システムは本質的に私たちのために行うことができます。

モジュールを使用すると、「高速単一ビルド」のケースが非常に簡単になります。 「クライアントのインスタンス化をサポートしますが、明示的にインスタンス化されたスペシャライゼーションのクライアントを再構築することは避けます」というケースではあまり機能しません。理論は、繰り返しの作業を回避することで一般的に高速なビルドは、さらに時間を節約するためにプログラムをゆがめる必要がなくなるということです。

あなたがすることは、明示的なインスタンス化definitionをモジュールインターフェースに置くことだけです:

export module A;
export template<class T>
inline void f(T &t) {++t;}
template void f(int&);
template void f(int*&);

関数テンプレートがinlineであっても、インポーターはこれら2つのタイプのどちらでもfをインスタンス化する必要はありません(非モジュールコードで追加のインスタンス化が必要になる場合があります)。典型的な実装では、インポーターで呼び出しをインライン化するのに十分な詳細でコンパイル済みモジュールインターフェースファイルにそれらのインスタンス化の結果をキャッシュします(さらに、インスタンス化するのに十分な詳細でテンプレート自体をキャッシュします)。

もちろん、明示的なインスタンス化declarationをインターフェイスのテンプレートの宣言だけで使用して、テンプレートを定義し、明示的なインスタンス化definitionsモジュール実装ユニット内ですが、ヘッダーファイルの動作と同じです。

2
Davis Herring