Sejak C++ tahun 1979-an, cara kita berbagi kode antar file hampir tidak berubah: header #include disalin-tempel secara tekstual oleh preprocessor ke setiap file yang memakainya. Mekanisme ini bekerja, tetapi warisannya terasa sampai sekarang — kompilasi ulang beruntun, pelanggaran ODR yang sulit dilacak, dan makro yang bocor ke mana-mana. C++20 memperkenalkan modules: unit kode yang diproses compiler sebagai satu kesatuan semantik, diekspor dan diimpor secara eksplisit, tanpa preprocessor di antaranya. Chapter ini menjelaskan masalah yang diselesaikan modules, sintaksnya, dan strategi migrasi — dengan satu catatan penting: toolchain course ini (g++ 14.2) belum mendukung modules, sehingga seluruh contoh adalah ilustrasi sintaks yang belum bisa kita kompilasi di sini.

Masalah yang Ditinggalkan Header #

Pertama, mari kita pangkas akar masalahnya: #include hanyalah perintah salin-tempel teks. Setiap unit translasi (file .cpp setelah preprocessor) mengulang seluruh proses parsing header yang sama — #include <string> di ratusan file berarti membaca dan mengurai header string ratusan kali, dan header proyek yang saling memuat memicu rantai kompilasi ulang setiap satu header berubah. Berikutnya ada dua masalah turunannya yang paling sering mengganggu. ODR (One Definition Rule) mudah dilanggar karena definisi non-inline yang sama di dua unit translasi hanya ketahuan saat tahap linking, dengan pesan “multiple definition” yang tidak menunjuk sumber sebenarnya. Dan makro tidak mengenal batas file:

cpp Ilustrasi kebocoran makro lewat header (pola nyata di proyek besar)
// konfigurasi.h — makro hidup global sejak baris ini
#define batasMaksimal 1000

// main.cpp
#include "konfigurasi.h"   // sejak baris ini, batasMaksimal "menempel" di mana-mana
#include <algorithm>       // header berikutnya ikut terpapar makro tersebut

int nilai = batasMaksimal;            // sah...
// int hasil = std::max(nilai, 5);    // ...dan bayangkan jika makronya bernama "max"

Makro tidak menghormati namespace, tidak bisa di-scoped, dan tetap hidup sampai baris terakhir unit translasi — atau sampai ada #undef yang berani memasangnya. Modules mengatasi ketiga masalah ini sekaligus karena satu hal mendasar: antarmuka module diekspor sebagai informasi semantik yang sudah di-parsing, bukan teks yang disalin.

Sintaks Dasar: export module dan import #

Struktur module terdiri atas interface unit (deklarasi yang diekspor) dan implementation unit (isi yang boleh disembunyikan). Berkas ilustrasi-modul.cpp di bundle chapter ini memuat contoh lengkap interface-nya; bentuk intinya seperti ini:

cpp Ilustrasi interface unit — butuh GCC 15+ / Clang 16+ / MSVC 19.28+
module;               // fragment global: tempat #include tradisional
#include <vector>

export module matematika;   // deklarasi nama module ini

export int tambah(int a, int b) {   // export = terlihat oleh importer
    return a + b;
}

Konsumennya jauh lebih ringkas daripada dunia header — satu baris import menggantikan satu header, tanpa include guard, tanpa forward declaration:

cpp Ilustrasi consumer unit
import matematika;            // menggantikan #include "matematika.h"

int main() {
    int hasil = tambah(2, 3);           // langsung terpakai
    return hasil == 5 ? 0 : 1;
}

Pemisahan interface dan isi juga dimungkinkan: unit kedua menyebut nama module yang sama tanpa kata export, dan apa pun yang tidak diekspor di sana tidak terlihat dari luar:

cpp Ilustrasi implementation unit
module matematika;    // tanpa "export": ini implementation unit

int helper(int a, int b) {   // hanya terlihat di dalam module
    return a * b;
}

Semua nama yang tidak diberi export — helper, konstanta internal, detail implementasi — otomatis menjadi privat module. Itu sebaliknya dari header, di mana semua yang tertulis pasti terlihat oleh yang meng-include.

Keuntungan Modules #

Ringkasan perbandingannya:

AspekHeader tradisionalModules
Cara kerjaSalin-tempel teks oleh preprocessorSemantik yang di-parsing sekali, diimpor
Kompilasi ulangRantai panjang; satu header berubah, banyak file ikutImporter tidak perlu kompilasi ulang dari perubahan isi module
ODRRawan “multiple definition” saat linkingDefinisi diekspor sekali dari satu unit
MakroBocor ke semua yang meng-includeTidak diekspor; tetap di unit asalnya
UrutanSensitif terhadap urutan includeUrutan import tidak berpengaruh
IsolasiSemua tertulis di header terlihatHanya yang di-export yang terlihat

Selain tabel di atas, ada dua bonus praktis: waktu kompilasi proyek besar turun signifikan karena header standar hanya di-parsing sekali, dan pesan error lebih relevan karena compiler melihat antarmuka module sebagai deklarasi sungguhan, bukan tumpukan teks.

Status Dukungan Compiler #

Modules adalah fitur C++20 yang paling lambat diadopsi toolchain, karena membutuhkan kerja sama compiler, pustaka standar, dan build system sekaligus. Per Oktober 2026, situasinya kira-kira:

CompilerDukungan modules
MSVC 19.28+Tersedia sejak 2020, paling matang; mendukung import std;
Clang 16+Didukung, termasuk import std; pada kombinasi pustaka yang tepat
GCC 15+Didukung penuh, termasuk import std;
GCC 14 (toolchain course)Belum mendukung — contoh di chapter ini hanya ilustrasi

Status terbaru selalu bisa dilihat pada tabel C++ compiler support di cppreference . Karena toolchain course ini masih GCC 14.2, tidak ada contoh {file=} yang diuji di chapter ini — semua kode di atas dibaca sebagai blueprint, bukan program yang bisa dijalankan di sini. Setelah lingkungan diperbarui ke GCC 15 atau lebih baru, contoh ilustrasi-modul.cpp siap dikompilasi tanpa perubahan.

Strategi Migrasi Bertahap #

Proyek nyata jarang bermigrasi sekaligus, dan standar memang merancang jalur bertahap. Urutan yang lazim:

  1. Awali dari fragment global: interface unit boleh memuat #include tradisional di fragment module;, sehingga module baru tetap bisa memakai header lama (lihat baris pertama contoh interface di atas).
  2. Modulkan pustaka internal yang paling stabil: pilih library internal yang sering di-include lintas tim, ekspor API-nya, dan sembunyikan detailnya.
  3. Gunakan header units sebagai jembatan: import <vector>; memperlakukan header standar sebagai module tanpa mengubah isinya — mode kompatibilitas yang bagus untuk header yang belum mau disentuh.
  4. Simpan import std; untuk akhir: ketika compiler dan build system sudah mendukung, satu baris ini menggantikan belasan include header standar.
  5. Perbarui build system: CMake 3.28+ mendukung module lewat FILE_SET CXX_MODULES; MSVC membutuhkan tanda /std:c++20 pada proyek yang bersangkutan. Dokumentasi resmi GCC 15 tentang modules mencatat detail per compiler.

Modules menuntaskan babak modernisasi tooling di section ini. Satu chapter tersisa untuk merangkum semuanya: bagaimana gaya menulis C++ yang benar-benar “modern” terlihat sehari-hari, dibuktikan dengan refactor nyata dari kode lama ke kode modern.

Rujukan resmi: cppreference — modules , GCC 15 — C++ Modules , cppreference — compiler support .