9
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

はじめに

C++20で導入されたモジュールシステムは、ヘッダーファイルの問題を解決する新しい仕組み。

インクルードガードとかプリプロセッサの闇から解放されるよ。

なぜモジュールが必要か

従来のヘッダーファイルの問題:

  • プリプロセッサによるテキスト置換
  • インクルードガードが必要
  • ビルド時間の増大
  • マクロの漏洩
  • ODR(One Definition Rule)違反のリスク

モジュールの基本

モジュールの作成

// math.ixx (モジュールインターフェースユニット)
export module math;

export int add(int a, int b) {
    return a + b;
}

export int multiply(int a, int b) {
    return a * b;
}

// 内部実装(エクスポートしない)
int internal_helper(int x) {
    return x * 2;
}

モジュールの使用

// main.cpp
import math;
#include <iostream>

int main() {
    std::cout << add(3, 4) << std::endl;       // 7
    std::cout << multiply(5, 6) << std::endl;  // 30
    // internal_helper(10);  // エラー!エクスポートされていない
    return 0;
}

モジュールパーティション

大きなモジュールを分割できます:

// math-add.ixx
export module math:add;

export int add(int a, int b) {
    return a + b;
}

// math-multiply.ixx
export module math:multiply;

export int multiply(int a, int b) {
    return a * b;
}

// math.ixx (プライマリモジュールインターフェース)
export module math;

export import :add;
export import :multiply;

モジュール実装ユニット

インターフェースと実装を分離:

// math.ixx (インターフェース)
export module math;

export int add(int a, int b);
export int multiply(int a, int b);

// math.cpp (実装)
module math;

int add(int a, int b) {
    return a + b;
}

int multiply(int a, int b) {
    return a * b;
}

グローバルモジュールフラグメント

従来のヘッダーを使う場合:

module;

// グローバルモジュールフラグメント
#include <iostream>
#include <vector>
#include <string>

export module mymodule;

export void greet(const std::string& name) {
    std::cout << "Hello, " << name << "!" << std::endl;
}

標準ライブラリモジュール (C++23)

// C++23
import std;  // 標準ライブラリ全体

int main() {
    std::cout << "Hello, Modules!" << std::endl;
    std::vector<int> v = {1, 2, 3};
    return 0;
}

// または
import std.compat;  // C互換ヘッダーも含む

モジュールのビルド

MSVC

cl /std:c++20 /experimental:module /c math.ixx
cl /std:c++20 /experimental:module main.cpp math.obj

GCC

g++ -std=c++20 -fmodules-ts -c math.ixx
g++ -std=c++20 -fmodules-ts main.cpp math.o

Clang

clang++ -std=c++20 -fmodules --precompile math.ixx -o math.pcm
clang++ -std=c++20 -fmodules -fprebuilt-module-path=. main.cpp math.pcm

CMake (3.28+)

cmake_minimum_required(VERSION 3.28)
project(ModuleDemo CXX)

set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

add_library(math)
target_sources(math
    PUBLIC FILE_SET cxx_modules TYPE CXX_MODULES FILES
    math.ixx
)

add_executable(app main.cpp)
target_link_libraries(app PRIVATE math)

モジュールの利点

従来のヘッダー モジュール
#include でテキスト挿入 import でバイナリ読み込み
複数回パース 一度だけコンパイル
マクロが漏洩 マクロは漏洩しない
インクルード順序依存 順序非依存
ODR違反のリスク 安全

ビルド時間の改善

従来のヘッダー: プリプロセス → パース → コード生成 (毎回)
モジュール: プリコンパイル済みモジュール読み込み (高速)

移行戦略

  1. 段階的移行: 新規コードからモジュール化
  2. ヘッダーユニット: 既存ヘッダーをモジュールのように使う
  3. import : ヘッダーをインポート形式で使用
// ヘッダーユニット
import <vector>;
import <string>;
import <iostream>;

現状の対応状況

コンパイラ 対応状況
MSVC 19.28+ ほぼ完全対応
GCC 11+ 実験的対応(-fmodules-ts)
Clang 16+ 対応進行中

注意点

  • ビルドシステムの対応が必要
  • コンパイラ間の互換性がまだ不完全
  • モジュールのビルド順序管理が必要

まとめ

C++20モジュールは、長年のヘッダーファイルの問題を解決する革新的な機能です。コンパイラとビルドシステムの対応が進めば、C++開発の標準的な方法になるでしょう。

9
0
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
9
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?