30
21

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

C++ Modulesの分割

Last updated at Posted at 2019-04-08

従来、C++ではプログラムをヘッダーファイルとソースファイルに分けることが行われてきました。

モジュール時代になると #include は使わなくなります。分割をしたいときは、モジュールを内部的なモジュールに分割するという形をとることになります。

Module unit

module unit とは、モジュールを構成する翻訳単位です。モジュール宣言を含む翻訳単位は module unit になります。

モジュール宣言
export module foo;

export キーワードがある場合、特に module interface unit と言います。ない場合をmodule implementation unitと言います。

ある1つのモジュールについて、 module interface unit となる翻訳単位はただ1つでなければいけません1。そのようなものを primary module interface unit といいます。

module implementation unitの数に制限はありません。

module interface unitは従来のヘッダーファイル、module implementation unitは従来のソースファイルのように使うのが自然だと思われます。

例えば、関数をヘッダーファイルで宣言してソースファイルで実装する場合、そのままmodule interface unitで宣言、module implementation unitで実装というように対応します。

Module partitions

module_name:part_name の書式でモジュール名をつけ、モジュールを分割できます。

module interface partitionsの宣言
export module foo:part;

このような宣言を含むファイルを module interface partitions と呼びます。

分割したモジュールはそれぞれ独立したモジュールとして振る舞いますが、モジュールが持っているクラスなどのエンティティは共有されます2

export をつけない場合、module implementation partitions になります。

module implementation partitionsの宣言
module foo:part;

module implementation partitions では、何もエクスポートしてはいけません3。分割したモジュール間ではエクスポートしていなくても宣言を参照できます。

分割したモジュールのインポート

分割したモジュールをインポートするときは、モジュール名を省略します。

module foo;
import :part;    // foo:partをインポート
import bar:part; // 文法エラー: 別のモジュールの一部をインポートするのは不可
import foo:part; // 文法エラー: 同じモジュールでも、:の前を書くのは不可

分割したモジュールの再エクスポート

module interface partitions の宣言を外から使えるようにするには、primary module interface unit から再エクスポートする必要があります4。module implementation partitions は再エクスポートできません5

export module foo;
export import :part;    // foo:partをインポートして再エクスポート
import :internal_part;  // foo:internal_partをインポート

まとめ

モジュール時代のライブラリの作り方は次のようになっていくと思われます。

従来のファイル構成 モジュールでの構成
1ヘッダー module interface unit
1ヘッダー+1ソースファイル (primary) module interface unit + module implementation unit
複数ヘッダー primary module interface unit + module interface partition
複数ヘッダー、複数ソース primary module interface unit + module implementation unit + module interface/implement partition
  • ヘッダーファイル/ソースファイルという単位の分割はしない
  • モジュールを分割することで内部的なものを非公開にする6

Module unitの分類

  • 翻訳単位
    • Module unit
      • Module interface unit
        • Primary module interface unit
          export module foo;
        • Module interface partitions
          export module foo:part;
      • Module implementation unit
        module foo;
        • Module implementation partitions
          module foo:part;

Module unitで出来ること

その翻訳単位からエクスポートできるか?

インターフェース 実装
モジュールユニット
モジュールパーティション

その翻訳単位を同一モジュール内でインポートできるか?

インターフェース 実装
モジュールユニット
モジュールパーティション

その翻訳単位を別モジュールからインポートできるか?

インターフェース 実装
モジュールユニット
モジュールパーティション

その翻訳単位を再エクスポートできるか?

インターフェース 実装
モジュールユニット
モジュールパーティション

参考文献

謝辞

この記事はC++20を相談しながら調べる会 #1の結果として書かれました。

  1. For a module foo, there must be exactly one translation unit whose preamble contains export module foo;

  2. Module interface partitions behave logically like distinct modules, except that they share ownership of contained entities with the module that they form part of.

  3. Module implementation partitions cannot contain exported declarations

  4. The primary module interface unit for a module is required to transitively import and re-export all of the interface partitions of the module.

  5. Module implementation partitions can be imported into the interface of a module, but cannot be exported.

  6. 分割せずともエクスポートしていないものはC++仕様レベルでは非公開ですが、ソースコード編集後の再コンパイルの掛かりやすさといった仕様外の観点では分割する意味があります。

30
21
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
30
21

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?