このページはC++26に採用される見込みの言語機能の変更を解説しています。
のちのC++規格でさらに変更される場合があるため関連項目を参照してください。
概要
C++20でモジュールが導入されたが、main()関数は名前付きモジュールに属することが禁止されていた。
C++26では、モジュール内でextern "C++"言語リンケージ指定を付けてmain()関数を定義することで、main()関数をグローバルモジュールに関連付けることが許可される。
// mymodule.cpp
module mymodule;
extern "C++" int main() {
// グローバルモジュールに関連付けられる
// モジュール内の非エクスポートな実体にアクセスできる
}
これにより、モジュール内の非エクスポートな実体をテストするために、テストコードをモジュール内に置くことが可能になる。
仕様
main()関数にextern "C++"言語リンケージ指定を付けることが許可されるextern "C++"言語リンケージ指定を付けたmain()関数は、名前付きモジュール内で定義されていてもグローバルモジュールに関連付けられるextern "C++"言語リンケージ指定なしでmain()関数を名前付きモジュールに属するように宣言することは、依然として不適格 (ill-formed) である
例
module;
#include <cassert>
export module mylib;
// エクスポートされる関数
export int add(int a, int b) {
return a + b;
}
// エクスポートされない内部関数
int internal_helper(int x) {
return x * 2;
}
// extern "C++"を付けることで、main関数をグローバルモジュールに関連付ける
// モジュール内の非エクスポートな実体にもアクセスできる
extern "C++" int main() {
assert(add(1, 2) == 3);
assert(internal_helper(5) == 10);
}
出力
この機能が必要になった背景・経緯
モジュール内の非エクスポートな実体をユニットテストする場合、テストコードはそのモジュールに属する必要がある。しかしC++20およびC++23では、main()関数は名前付きモジュールに属することが禁止されていたため、モジュール内にテスト用のmain()関数を直接書くことができなかった。
この問題に対して、P3422R1は「モジュール内のmain()を自動的にグローバルモジュールに関連付ける」という特別扱いを追加するアプローチを提案していた。一方、本提案 (P3618R0) は、既存のextern "C++"メカニズムを利用して明示的にグローバルモジュールへの関連付けを行うアプローチをとった。本提案はmain()への特別扱いを追加するのではなく、既存の特別扱い(main()に言語リンケージ指定を禁止していたこと)を削除するという、より一貫性のある設計となっている。
検討されたほかの選択肢
P3422R1では、モジュール内で定義されたmain()関数を暗黙的にグローバルモジュールに関連付けるアプローチが提案されていた。これはmain()への新たな特別扱いの追加であり、本提案 (P3618R0) は既存のextern "C++"を利用する明示的なアプローチの方が言語の一貫性を保てるとして、こちらが採用された。