🫅

ついに投入されたモジュール機能

に公開

C/C++ の他のプログラミング言語との大きな違いは、コードをヘッダーファイルとソースファイルに分けることだと思います。私の知っている限りヘッダーファイルを使うのは C/C++ のみです。宣言と定義を分けることは他のプログラミング言語でも見かけますが、C/C++ のように徹底的に別のファイルに分けているのは見たことがないです。

.hcppに分けるには色々理由があると思いますが、C/C++ の説明を見るとメリットだけ並べてありますが、以下のようなデメリットもあります。

  • ヘッダーファイルとソースファイルという2つのファイルを使わないといけなくて、ダブルメンテになります。
  • ヘッダーファイルに宣言だけではなく定義まで含まれていると多重定義でリンカーエラーになりかねないです。
  • ヘッダーファイルに#ifndef#pragmaでインクルードガードを入れないと多重定義でリンカーエラーになりかねないです。
  • 2つのヘッダーファイルがお互いをインクルードすると、循環参照エラーになります。

違うプログラミング言語に慣れている人からすると「そもそもなんで使っているの?」ってなると思います。あんなにメリットがあるのであれば、なんで他のプログラミング言語もヘッダーファイルを使わないのですか?
答えは簡単です。C++ は40年以上前の言語なのです。当時は宣言と定義を分けるために別々のファイルにするのが一番いい解決方法だったかもしれいないですが、もっと新しいプログラミング言語は大体モジュールとパッケージを使っています。

でも C++ の個人的にいいと思うところは今でも新しいアイデアを積極的に取り入れようとしている方針です。

C++20 からはmodulesという機能が追加されました。まだどのコンパイラにも完全にサポートされていなさそうですが、サポートされるようになったら、.hはファイルはもう使わないようになり、.cppファイルだけが残るかもしれないです。 C++ のコードがガラッと変わる可能性があります。

modulesは以下のように使います。

A.cpp(モジュールファイル)

export module A; // module A の宣言
 
import <iostream>; // エクスポートされない
export import <string_view>; // エクスポートされる
 
export void print(std::string_view message) // エクスポートされる
{
    std::cout << message << std::endl;
}
main.cpp
import A; // module A をインポート
 
int main()
{
    std::string_view message = "Hello, world!";
    print(message);
}

ご覧のようにモジュールファイルの中でエクスポートしたい定義の前にexportを付けます。exportが付いていない定義はエクスポートされないです。モジュールをインポートするimportコマンドもエクスポートされるように設定できます。
この例では、モジュールAからは<string_view>のインポートとprintという関数がエクスポートされていて、モジュールAをインポートすることで、<string_view>printが使えるようになっています。

gcc 14.2.0 では以下のようにコンパイルできました。

// まずは iostream と string_view のモジュールをビルドする
// これによって gcm.cache というディレクターの中にモジュールファイルが作成される
g++ -std=c++20 -fmodules-ts -x c++-system-header iostream
g++ -std=c++20 -fmodules-ts -x c++-system-header string_view
// そして A.cpp と main.cpp をビルドする
g++ -std=c++20 -fmodules-ts A.cpp main.cpp -o modules_test

C++ がガラッと変わるからこそ、コンパイラー側の実装も非常に大変だと思います。C++20 で未だにメジャーなコンパイラに完全にサポートされていない機能はmodulesのみです。

さっきは C++ のいいところは積極的に新しいアイデアを取り入れることだと書いたのですが、どうしても後方互換性のしがらみが残るのが C++ の悪い(辛い)ところ、かもしれません。つまり「modulesを使ってもいいし、使わなくてもいい」、という状態になります。
もちろんそれが C++ の良いところいう人もいますが、同じ C++ でもプログラマーや環境によって、殆ど別言語のようになってしまうのは宜しくないです。

modulesに関しては、C++ を使っている人がみんな使ってくれないと意味がないです。今まで通りヘッダーファイルを使い続けるか、modulesに切り替えるかの2択になるので、modulesがコンパイラーにサポートされるようになっても、ユーザーが使ってくれるかは怪しいですね。
私は絶対に使ってみたいです。


|cpp記事一覧へのリンク|

Discussion