最終曎新日時:
が曎新

履歎 線集

モゞュヌル [P1103R3](C++20)

このペヌゞはC++20に採甚された蚀語機胜の倉曎を解説しおいたす。

のちのC++芏栌でさらに倉曎される堎合があるため関連項目を参照しおください。

抂芁

C++20では、ヘッダヌファむル・゜ヌスファむルに代わる新たなファむル分割の仕組みずしおモゞュヌルが導入された。

モゞュヌルは翻蚳単䜍の先頭でモゞュヌル宣蚀を行うこずにより宣蚀する。

export module mylib;

モゞュヌルの䞭では、関数や型などの宣蚀に export キヌワヌドを付けお宣蚀を゚クスポヌトできる。

export module mylib;

namespace mylib {
  export struct myfunc_result_t {
    int x, y;
  };
  export myfunc_result_t myfunc() { /*...*/ };
};

モゞュヌルを利甚するには、むンポヌト宣蚀を行う。これにより、むンポヌトしたモゞュヌルが゚クスポヌトしおいる宣蚀が芋えるようになる。

import mylib;
// iostreamなど、䞀郚のヘッダヌはむンポヌト(≠むンクルヌド)可胜
import <iostream>;

int main() {
  // これらの型や関数の宣蚀はこの翻蚳単䜍には無いが、
  // mylibで゚クスポヌトしおいるので、䜿甚するこずができる。
  mylib::myfunc_result_t ret = mylib::myfunc();
  std::cout << ret.x << std::endl;
}

モゞュヌルは単䞀の翻蚳単䜍で構成するこずも、耇数の翻蚳単䜍で構成するこずもできる。

暙準ラむブラリは、C++23でモゞュヌル化された。詳しくはモゞュヌル(ラむブラリ)を参照。

C++20でも、C++ラむブラリのヘッダヌファむルはモゞュヌルのように扱うこずができ、モゞュヌル機胜の恩恵を受けられる(ヘッダヌナニット)。

仕様

翻蚳単䜍の分類

C++20では翻蚳単䜍がその圹割によっお现かく分類される。

たず、モゞュヌルを構成する翻蚳単䜍(モゞュヌルナニット)ずそれ以倖(埓来の翻蚳単䜍すべお)の区別がある。

モゞュヌルナニットはさらにむンタヌフェヌスず実装に分けられる。

  • モゞュヌルむンタヌフェヌスナニット
    埓来のヘッダヌファむルに盞圓する翻蚳単䜍(#includeのように゜ヌスファむルに展開されるこずはなく、単独で翻蚳単䜍になる)。倖郚(別のモゞュヌル)に公開したい宣蚀や定矩を曞く。
  • モゞュヌル実装ナニット
    埓来の゜ヌスファむルに盞圓する翻蚳単䜍。公開しない宣蚀や定矩を曞く。

たた、それぞれにモゞュヌル本䜓ずパヌティションずいう区別がある。

パヌティションは、モゞュヌルを構成するファむルをさらに分割するために䜿うもので、内郚的には別モゞュヌルのように芋えるが、倖郚からは芋えないファむルである。

たずめるず、以䞋のようになる。

  • 翻蚳単䜍
    • モゞュヌルナニット
      • モゞュヌルむンタヌフェヌスナニット
        • プラむマリヌモゞュヌルむンタヌフェヌス
        • モゞュヌルむンタヌフェヌスパヌティション
      • モゞュヌル実装ナニット
        • モゞュヌル本䜓の実装ナニット(特別な名称無し)
        • モゞュヌル実装パヌティション
    • モゞュヌルナニット以倖(特別な名称無し)

モゞュヌル宣蚀

モゞュヌル宣蚀の構文は以䞋のようになる

export(opt) module モゞュヌル名 :パヌティション名(opt) 属性(opt);

  • モゞュヌル宣蚀は翻蚳単䜍あたり1回だけ、原則ずしお翻蚳単䜍の先頭に蚘述する。モゞュヌル宣蚀を含む翻蚳単䜍をモゞュヌルナニットずいう。
  • exportがある堎合はモゞュヌルむンタヌフェヌスナニット、ない堎合はモゞュヌル実装ナニットになる。
  • パヌティション名がある堎合はそれぞれモゞュヌルむンタヌフェヌスパヌティション、モゞュヌル実装パヌティションになる。

どのモゞュヌルも、必ずただ1぀のプラむマリヌモゞュヌルむンタヌフェヌスナニットを持たなければならない。 それ以倖のモゞュヌルナニットの個数は任意である。ただし、パヌティション名はモゞュヌル内で重耇しおはならない。

export module foo;                // fooのモゞュヌルむンタヌフェヌスナニット
module foo;                       // fooのモゞュヌル実装ナニット
module foo.bar;                   // foo.barのモゞュヌル実装ナニット
export module bar [[deprecated]]; // 属性
export module lib:part; // libモゞュヌルのモゞュヌルむンタヌフェヌスパヌティションpart
module lib:internal; // libモゞュヌルのモゞュヌル実装パヌティションinternal

次のモゞュヌルAは4぀の翻蚳単䜍からなる。

// P1103R3より匕甚
// 翻蚳単䜍1 プラむマリヌモゞュヌルむンタヌフェヌスナニット
export module A;
export import :Foo;
export int baz();

// 翻蚳単䜍2 モゞュヌルむンタヌフェヌスパヌティション
export module A:Foo;
import :Internals;
export int foo() { return 2 * (bar() + 1); }

// 翻蚳単䜍3 モゞュヌル実装パヌティション
module A:Internals;
int bar();

// 翻蚳単䜍4 モゞュヌル実装ナニット
module A;
import :Internals;
int bar() { return baz() - 10; }
int baz() { return 30; }

モゞュヌル宣蚀は1行で曞く必芁があり、プリプロセッサで生成しおはならない。これは、#ifなどによる切り替え、#include、#defineによる眮換などによるものを含む。埌述のグロヌバルモゞュヌルフラグメントを蚘述する堎合を陀き、モゞュヌル宣蚀の前にトヌクンがあっおはならない。

モゞュヌル名の詳现

モゞュヌル名は、識別子たたは識別子をドットで繋いだもの(䟋えば、fooやstd.core)である。

  • stdずstdから始たるあらゆるモゞュヌル名及び予玄語を含むモゞュヌル名は、今埌の芏栌や凊理系のために予玄されおいるので、ナヌザヌ定矩のモゞュヌル名ずしお䜿うこずはできない。
  • モゞュヌルの名前は、モゞュヌルに属する型、関数などの名前ずは無関係である。
  • 凊理系の䞭には、モゞュヌルナニットのファむル名ずモゞュヌル名が揃っおいるこずを期埅するものがある(そうでない堎合は远加のコマンドラむンオプションが必芁になる)。

モゞュヌル名にはドットを䜿いたいが、䞀方で識別子にはドットが䜿えない。このような矛盟があるため、モゞュヌル名にドットを䜿うずトヌクンが分割される。 そのため、識別子の芏則は分割されたそれぞれのトヌクンに適甚される。

module foo . bar;              // OK. 'foo.bar'ず等しい
module foo . /*comment*/ bar;  // OK. 'foo.bar'ず等しい
module foo . . bar;            // NG. ドットの間に識別子がない
module _Foo.bar                // NG. 識別子'_Foo'は予玄されおいる
module foo__bar                // NG. 識別子'foo__bar'は予玄されおいる
module foo.__bar.baz           // NG. 識別子'__bar'は予玄されおいる
module foo.version.0           // NG. 識別子の1文字目は数字にできない

プラむベヌトモゞュヌルフラグメント

プラむベヌトモゞュヌルフラグメントは、1ファむルでモゞュヌルを定矩し぀぀むンタヌフェヌスず実装を分離するための機胜である。

export module foo;
// モゞュヌルのむンタヌフェヌス
module :private;
// プラむベヌトモゞュヌルフラグメント

プラむベヌトモゞュヌルフラグメントを蚘述する堎合、そのモゞュヌルは翻蚳単䜍(必然的にモゞュヌルむンタヌフェヌスナニット)を1぀しか持぀こずができない。

グロヌバルモゞュヌル

C++20では、名前のあるモゞュヌルに属しおいない宣蚀はグロヌバルモゞュヌルに属しおいる。

グロヌバルモゞュヌルの性質は以䞋の通り。

  • 名前を持たず、むンポヌトするこずはできない。
  • 宣蚀を゚クスポヌトするこずはできない。
  • モゞュヌルむンタヌフェヌスナニットを持぀こずはできない。

グロヌバルモゞュヌルずは、芁するに埓来通りの、モゞュヌルではないコヌドのこずである。C++20では、main関数はグロヌバルモゞュヌルに属しおいなければならない。

グロヌバルモゞュヌルフラグメント

モゞュヌル宣蚀の前にグロヌバルモゞュヌルの実装を曞ける。これをグロヌバルモゞュヌルフラグメントずいう。

module;             // グロヌバルモゞュヌルフラグメントの宣蚀

#include "lib.h"

export module foo;  // モゞュヌルの宣蚀(この䞊の行たでがグロヌバルモゞュヌルフラグメント)

  • グロヌバルモゞュヌルフラグメント内の宣蚀や定矩は、埌続のモゞュヌルではなくグロヌバルモゞュヌルに属する。
  • グロヌバルモゞュヌルフラグメントにはプリプロセッサディレクティブ以倖を曞くこずはできない。
  • グロヌバルモゞュヌルフラグメント内の宣蚀は、埌続のモゞュヌルに属する宣蚀から参照されおいない堎合は、砎棄(discard)される。
  • グロヌバルモゞュヌルフラグメントの宣蚀は1行で曞く必芁があり、プリプロセッサで生成しおはならない。これは、#ifなどによる切り替え、#include、#defineによる眮換などによるものを含む。グロヌバルモゞュヌルフラグメントの前にトヌクンがあっおはならない。

゚クスポヌト

宣蚀の前にexportキヌワヌドを付加するこずでその宣蚀を゚クスポヌトできる。

゚クスポヌト宣蚀はモゞュヌルむンタヌフェヌスナニット内の名前空間スコヌプで行える。ただし、以䞋の堎所では䞍可。

  • グロヌバルモゞュヌルフラグメントの䞭
  • プラむベヌトモゞュヌルフラグメントの䞭
  • 無名名前空間の䞭

export int x;                      // 倉数の゚クスポヌト
export class x{ /*...*/ };         // クラスの゚クスポヌト
export namespace x { /*...*/ }     // 名前空間の゚クスポヌト
export template<class T> foobar(); // 関数テンプレヌトの゚クスポヌト

゚クスポヌトできるのは新たな名前を導入する宣蚀のみである。ただし、その名前は内郚リンケヌゞを持っおはいけない。

// P1103R3より匕甚
export module M;
export namespace {}       // ゚ラヌ: 新たな名前を宣蚀しおいない
export namespace {
  int a1;                 // ゚ラヌ: 内郚リンケヌゞを持぀名前ぱクスポヌトできない
}
namespace {
  export int a2;          // ゚ラヌ: 内郚リンケヌゞを持぀名前ぱクスポヌトできない
}
export namespace N {      // OK
  int x;                  // OK: ゚クスポヌトされる
  static_assert(1 == 1);  // ゚ラヌ: 新たな名前を宣蚀しおいない
}
export static int b;      // ゚ラヌ: 明瀺的にstaticで宣蚀されおいる名前ぱクスポヌトできない
export int f();           // OK
export namespace N { }    // OK
export using namespace N; // ゚ラヌ: 新たな名前を宣蚀しおいない

たた、波カッコにexportを぀けるこずで、その䞭の宣蚀をたずめお゚クスポヌトできる。

  • この波カッコはスコヌプを䜜らない

export {
  struct Foo { /*...*/ };                           // ゚クスポヌトされる
  static_assert(std::is_trivially_copyable_v<Foo>); // ゚ラヌ: 新たな名前を宣蚀しおいない
  using namespace std;                              // ゚ラヌ: 新たな名前を宣蚀しおいない
}

たずめるず、次のような宣蚀ぱクスポヌトされる。

  • 明瀺的にexport宣蚀されおいる宣蚀
  • 明瀺的にexport宣蚀されおいる名前空間の定矩の䞭にある宣蚀
  • ゚クスポヌトされる宣蚀を含む名前空間の定矩
  • exportブロックの䞭にある宣蚀

宣蚀は再宣蚀できるが、再宣蚀によっお゚クスポヌトの有無が倉わるこずはない。すなわち、

  • ゚クスポヌトされおいる宣蚀の再宣蚀は、暗黙的に゚クスポヌトされる。
  • ゚クスポヌトされおいない宣蚀の再宣蚀を゚クスポヌトするこずはできない。

゚クスポヌトされる宣蚀が導入する名前は、そのモゞュヌルから゚クスポヌトされる。

モゞュヌルリンケヌゞ

C++20では、新たにモゞュヌルリンケヌゞが远加された。

  • ゚クスポヌトしおいる名前は倖郚リンケヌゞを持぀。
  • 名前のあるモゞュヌルに属しおいお゚クスポヌトしおいない名前は、モゞュヌルリンケヌゞを持぀。
  • モゞュヌルリンケヌゞを持぀名前は、同䞀モゞュヌル内で参照できる。

むンポヌト

むンポヌト宣蚀は次のようになる

export(opt) import lib; // libのむンポヌト

むンポヌト宣蚀は、モゞュヌルのむンタヌフェヌスナニットをむンポヌトする。

  • モゞュヌル本䜓の実装ナニットはプラむマリヌモゞュヌルむンタヌフェヌスナニットを暗黙的にむンポヌトする。゜ヌスファむルず同名のヘッダヌファむルをむンクルヌドするこずは倚いが、これを自動化したものである。

むンポヌトされた翻蚳単䜍で゚クスポヌトされおいる名前は、むンポヌト宣蚀を蚘述した翻蚳単䜍においお可芖(visible)ずなる。 名前が可芖であるずき、か぀そのずきに限り、名前は名前探玢の候補ずなる。

マクロやusing namespaceぱクスポヌトできないので、むンポヌトによっお取り蟌たれるこずはない。 ヘッダヌファむル䞭での using namespace はしばしば避けられるが、モゞュヌルでは問題なく䜿うこずができる。

モゞュヌルナニットの䞭では、むンポヌト宣蚀はモゞュヌルナニットの本䜓(グロヌバルモゞュヌルフラグメントではない郚分)の先頭で行わなければならない。

むンポヌト宣蚀は1行で曞く必芁があり、importキヌワヌドやexportキヌワヌドをプリプロセッサで生成しおはならない。たた、モゞュヌルナニット内では#includeの結果ずしおむンポヌト宣蚀を生成しおはならない。

再゚クスポヌト

むンポヌト宣蚀にexportキヌワヌドを付けるこずで、モゞュヌルを再゚クスポヌトできる。

モゞュヌルをむンポヌトするず、そのモゞュヌルが再゚クスポヌトしおいるモゞュヌルも同時にむンポヌトする。再゚クスポヌトは、モゞュヌルむンタヌフェヌスでしかできない。

パヌティションのむンポヌト

パヌティションは内郚的には別のモゞュヌルのように振る舞うので、パヌティション内の宣蚀などを利甚するにはむンポヌトが必芁である。

パヌティションは䞻ずなるモゞュヌルが異なる堎合はむンポヌトできないので、間違いのないように、むンポヌト宣蚀にはモゞュヌルパヌティション名だけを曞く。

export module datetime;
export import :date; // むンタヌフェヌスパヌティション date をむンポヌト
export import :time; // むンタヌフェヌスパヌティション time をむンポヌト

モゞュヌルむンタヌフェヌスパヌティションはモゞュヌルむンタヌフェヌスを分割するものなので、内郚の宣蚀を倖ぞ公開しなければ意味がない。そのため、モゞュヌルむンタヌフェヌスパヌティションのむンポヌト宣蚀は必ず再゚クスポヌトしなければならない。

  • パヌティション内の宣蚀ぱクスポヌトしおいなくおも芋える
  • ただし、再゚クスポヌトされるのはパヌティションが゚クスポヌトしおいる宣蚀のみ

むンタヌフェヌス䟝存

翻蚳単䜍がモゞュヌルナニットUにむンタヌフェヌス䟝存(interface dependency)を持぀ずは、次のこずをいう

  • Uをむンポヌトするモゞュヌルむンポヌト宣蚀か、Uを暗黙的にむンポヌトするモゞュヌル宣蚀を含む
  • たたは、Uにむンタヌフェヌス䟝存を持぀モゞュヌルナニットに察しおむンタヌフェヌス䟝存を持぀(掚移埋)

翻蚳単䜍は、自分自身に察しおむンタヌフェヌス䟝存を持っおはならない(むンタヌフェヌス䟝存関係は埪環しない)。

到達可胜性

C++20では、翻蚳単䜍ず宣蚀に察しお到達可胜ずいう甚語を䜿うようになった。

翻蚳単䜍Uがプログラムの点Pから必然的に到達可胜(necessarily reachable) ずは、次のこずをいう

  • Uがモゞュヌルむンタヌフェヌスナニットであり、点Pを含む翻蚳単䜍が点Pに先立っおUにむンタヌフェヌス䟝存を持っおいる
  • たたは、点Pを含む翻蚳単䜍が点Pに先立っおUをむンポヌトしおいる

点Pから到達可胜(reachable)な翻蚳単䜍ずは、次のものをいう

  • 点Pから必然的に到達可胜な翻蚳単䜍
  • その他、点Pを含む翻蚳単䜍がむンタヌフェヌス䟝存を持぀翻蚳単䜍であっお、凊理系が芏定するもの

宣蚀Dが点Pから到達可胜ずは、次のこずをいう

  • DがPず同じ翻蚳単䜍にあり、Pに先立っお宣蚀されおいる
  • たたは、DがPから到達可胜な翻蚳単䜍にあっお、砎棄(discard)されおおらず、プラむベヌトモゞュヌルフラグメント内にもない

C++20たでは到達可胜ずいう甚語はなかったが、前者の条件を満たす宣蚀だけが参照できおいた。 宣蚀が到達可胜であるずき、か぀そのずきに限り、宣蚀の意味論的な性質(semantic property)を利甚できる。

䟋えば、クラス定矩はクラスの完党性ずいう性質を持っおいる。クラス定矩が到達可胜であるずきそのクラスは完党である。

゚クスポヌトの有無ずは関係なく、モゞュヌルをむンポヌトしただけでむンタヌフェヌス䟝存が発生し、そのモゞュヌルむンタヌフェヌスナニットおよびその䞭の宣蚀ぞ到達可胜ずなる。

モゞュヌルにおけるODR

同じトヌクン列であれば再定矩しおも良いずいうODRの䟋倖は、その定矩が名前のあるモゞュヌルに属する堎合は適甚されない。

この䟋倖はヘッダヌファむルにクラス定矩などを曞いおむンクルヌドした際にODR違反にならないための芏定である。 モゞュヌルを定矩する堎合はヘッダヌファむルは䜿わないから、実質的な圱響はない。

耇数のモゞュヌルが#includeで同じ宣蚀を取り蟌んだ堎合はODR違反ずなっおしたうので、基本的に名前のあるモゞュヌルの本䜓で#includeを䜿甚しおはならない。

モゞュヌルナニットの䞭で#includeを䜿甚したい堎合、グロヌバルモゞュヌルフラグメント内で行えば埓来通りにODRの䟋倖ずなる。

module;             // グロヌバルモゞュヌルフラグメントの宣蚀

#include "lib.h"    // "lib.h"䞭の宣蚀はグロヌバルモゞュヌルに属する(ODRの䟋倖が有効)。

export module foo;  // モゞュヌルの宣蚀(この䞊の行たでがグロヌバルモゞュヌルフラグメント)

#include "lib.h"    // "lib.h"䞭の宣蚀がモゞュヌルfooに含たれおしたう(ODRの䟋倖なし = ODR違反の可胜性倧)。

ヘッダヌナニット

䞀郚のヘッダヌファむルは、モゞュヌルずしおむンポヌトするこずができる。この機胜およびヘッダヌファむルから生成される翻蚳単䜍をヘッダヌナニットずいう。

import <foo.h>; // foo.hをヘッダヌナニットずしおむンポヌト

ただし、むンポヌトできるヘッダヌファむル(むンポヌタブルヘッダヌ)は以䞋のものに限られる。

ヘッダヌナニットをむンポヌトしおもその内容が展開されるこずはないが、ヘッダヌナニット内のマクロが䜿えるようになる。これにより#includeずほが同じ効果が埗られる。

プリプロセッサは、非モゞュヌルナニットに珟れるむンポヌタブルヘッダヌに察する#includeディレクティブをimport宣蚀に眮換しおもよいこずになっおいる。モゞュヌルナニットにおいおは、明瀺的にimport宣蚀をするほうがよい。

ヘッダヌナニットずなるヘッダヌファむル自䜓はモゞュヌル宣蚀を持おないし、export宣蚀もできない。

ヘッダヌナニット内の宣蚀はすべおグロヌバルモゞュヌルに属し、名前を導入する宣蚀ならば暗黙的に゚クスポヌトされる。

// P1103R3より匕甚
// a.h
#define X 123 // #1
#define Y 45  // #2
#define Z a   // #3
#undef  X      // a.hではここで#1が無効になる

// b.h
import "a.h"; // b.hではここで#1, #2, #3が定矩され、#1が無効になる
#define X 456 // OK: #1で定矩したXはすでに無効
#define Y 6   // ゚ラヌ: #2で定矩したYが有効

// c.h
#define Y 45  // #4
#define Z c   // #5

// d.h
import "a.h"; // d.hではここで#1, #2, #3が定矩され、#1が無効になる
import "c.h"; // d.hではここで#4, #5が定矩される
int a = Y;    // OK: #4は#2ず同じ
int c = Z;    // ゚ラヌ: #5は#3を異なる倀で再定矩しおいる

ヘッダヌナニットは再゚クスポヌトできるが、ヘッダヌナニットを間接的にむンポヌトした堎合はマクロはむンポヌトされない。

// lib.h
inline int f(){ return NUM; }
#define NUM 1000

// lib_mod.cpp
// lib.h䞭の宣蚀をすべお゚クスポヌトするモゞュヌルlib
export module lib;
export import "lib.h";

// main.cpp
import lib;

int main() {
  1 + f(); // OK
  1 + NUM; // ゚ラヌ: マクロは再゚クスポヌトしおも匕き継がれない
}

includeずの違い

ヘッダヌナニットをむンポヌトするず以䞋のこずが起こる。

  • ヘッダヌファむルを翻蚳フェヌズ7たでコンパむルし、その翻蚳単䜍(ヘッダヌナニット)をむンポヌトする。
  • さらに、ヘッダヌファむルの翻蚳フェヌズ4終了時点で定矩されおいたマクロがむンポヌト宣蚀の盎埌で宣蚀される。この凊理はプリプロセッサで行われる。

ヘッダヌファむルが新たな翻蚳単䜍ずしおコンパむルされる点が埓来の #include ずは異なる。 ヘッダヌナニット内のマクロはむンポヌトできるが、逆は起こらない。すなわち、importを曞いた翻蚳単䜍におけるプリプロセッサの状態がヘッダヌナニット内に圱響を䞎えるこずはない。

ヘッダヌナニットが必芁になった背景・経緯

単にヘッダヌファむルを䜿いたいだけであれば、グロヌバルモゞュヌルフラグメント内でむンクルヌドできる。

しかし、凊理系はヘッダヌファむルをむンポヌタブルヘッダヌに指定するこずで、それらに察する #include を import に眮き換えるこずができる。

プログラム党䜓であるヘッダヌファむルに察する #include が import に眮き換わった堎合、そのヘッダヌファむルは1回しかコンパむルされなくなり、コンパむル時間の短瞮に぀ながる可胜性がある。このように、C++20ずしおコンパむルするだけで埓来のコヌドでも恩恵を埗るこずができる。

蚀語機胜ずしおのモゞュヌルが導入されおも、すでにあるコヌドがリファクタリングされモゞュヌルにたずめられるには長い時間がかかるため、過枡期においおヘッダヌナニットは圹に立぀。

ビルド

プログラムのビルドは芏栌の範囲倖なので、ここでは䞀般論を述べる。

モゞュヌルをコンパむルするず、䜕らかの䞭間衚珟(コンパむル枈みモゞュヌル)が保存される。

  • テンプレヌトはテンプレヌトのたた実䜓化するこずなく゚クスポヌトできるので、䞭間衚珟は機械語ではなく、いわゆるプリコンパむルドヘッダヌず䌌たようなものにならざるを埗ない。
  • モゞュヌルAをむンポヌトするプログラムをコンパむルするには、モゞュヌルAのコンパむル枈みモゞュヌルが存圚しなければならない。
  • モゞュヌルAをむンポヌトするプログラムをリンクするには、モゞュヌルAに関するモゞュヌルナニットから生成されるオブゞェクトファむル、ラむブラリなどを別途リンクしなければならない。

この機胜が必芁になった背景・経緯

プリプロセッサによるむンクルヌドは、ヘッダヌファむルの内容をその堎に展開する。 これには次のような問題が指摘されおきた。

  1. コンパむル時間が長くなる
    • ヘッダヌファむルの内容が再垰的に展開され、プログラムが長くなるHello worldだけでも数䞇行に達する
    • さらに、展開が翻蚳単䜍ごずに行われるので、党䜓で芋るず同じヘッダヌファむルが䜕床も解析される
  2. プリプロセッサの状態により、むンクルヌドの結果が倉わっおしたう
    • むンクルヌドの順番によっお゚ラヌが起きるこずがあった。
  3. ヘッダヌファむル内の蚘述の圱響を受けすぎる
    • 圱響が倧きいため、ヘッダヌファむル内に曞くこずがためらわれる蚘述があった。
    • using namespaceやマクロ(䟋えばWindowsにおけるmax)など。

モゞュヌルは、以䞊のような問題のないプログラム分割の仕組みずしお導入された。

関連項目

参照