Language
日本語
English

Caution

JavaScript is disabled in your browser.
This site uses JavaScript for features such as search.
For the best experience, please enable JavaScript before browsing this site.

  1. Home
  2. C++ Dictionary
  3. modules

modules

C++20 modules replace the traditional header-file-plus-preprocessor-include mechanism with a new compilation unit management system. Modules eliminate repeated text expansion of headers, shorten build times, prevent macro pollution, and give explicit control over what is exported.

Syntax

// --- Module interface file (.cppm or .ixx) ---

// Declare the module name; "export module" makes this an interface unit
export module mylib;

// Add "export" to declarations and definitions visible outside the module
export int add(int a, int b) {
    return a + b;
}

// Identifiers without "export" are module-private
int helper(int x) {
    return x * 2;
}

// Export block: export multiple declarations at once
export {
    int multiply(int a, int b);
    double divide(double a, double b);
}

// --- Module implementation file (.cpp) ---

// Declare the same module name without "export" to create an implementation unit
module mylib;

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

// --- Consumer file (.cpp) ---

// Use "import" to load the module (no #include needed)
import mylib;

int main() {
    int result = add(3, 4);
    // helper(5);  // compile error: not exported
    return 0;
}

Syntax Reference

Syntax / ConceptDescription
export module name;Declares a module interface unit. Place this at the top of the file that defines the module's public API.
module name;Declares a module implementation unit. Written without "export". The function/class implementations go here.
import name;Loads a module. Unlike #include, it references pre-compiled module information, making builds faster.
export declaration;Makes a function, class, variable, or type alias visible outside the module. Identifiers without export are module-private.
export { ... }Export block. Exports multiple declarations at once instead of prefixing each with export.
module :private;Private module fragment. Everything after this line is completely invisible outside the module.
import <header>;Imports a standard library header in module form. Implementation-defined, but more efficient than #include.

Sample Code

An organization management library modeled on Yakuza (Like a Dragon) characters, implemented as a module. The project uses three files: an interface unit, an implementation unit, and a consumer.

First, create the interface unit (.cppm or .ixx) that defines the module's public API.

yakuza_org.cppm
// yakuza_org.cppm
// Organization management module using Yakuza characters.
// This file defines the module's public interface.

export module yakuza_org;

#include <string>
#include <vector>

// Exported struct: Member
export struct Member {
    std::string name;
    std::string role;
    int         strength;
};

// Exported class: YakuzaOrg
export class YakuzaOrg {
public:
    explicit YakuzaOrg(const std::string& orgName);
    void   addMember(const Member& m);
    void   showAll() const;
    Member strongest() const;

private:
    std::string         orgName_;
    std::vector<Member> members_;
};

// Exported utility function
export void printMember(const Member& m);

// Module-private helper (not exported)
std::string formatStrength(int strength);

Next, create the module implementation unit (.cpp) that contains the implementations declared in the interface.

yakuza_org.cpp
// yakuza_org.cpp
// Implementation unit for the yakuza_org module.

module yakuza_org;

#include <iostream>
#include <string>
#include <stdexcept>

// Module-private helper implementation
std::string formatStrength(int strength) {
    if (strength >= 90) return "[Legend]";
    if (strength >= 70) return "[Executive]";
    if (strength >= 50) return "[Mid-level]";
    return "[General]";
}

YakuzaOrg::YakuzaOrg(const std::string& orgName) : orgName_(orgName) {}

void YakuzaOrg::addMember(const Member& m) {
    members_.push_back(m);
}

void YakuzaOrg::showAll() const {
    std::cout << "=== " << orgName_ << " Members ===" << std::endl;
    for (int i = 0; i < (int)members_.size(); i++) {
        printMember(members_[i]);
    }
    std::cout << std::endl;
}

Member YakuzaOrg::strongest() const {
    if (members_.empty()) {
        throw std::runtime_error("No members registered.");
    }
    Member best = members_[0];
    for (int i = 1; i < (int)members_.size(); i++) {
        if (members_[i].strength > best.strength) {
            best = members_[i];
        }
    }
    return best;
}

void printMember(const Member& m) {
    std::cout << "  " << formatStrength(m.strength)
              << " " << m.name
              << " (" << m.role << ")"
              << "  Strength: " << m.strength << std::endl;
}

Finally, create the consumer file that imports the module and uses it.

main.cpp
// main.cpp
// Imports yakuza_org and uses the exported types and functions.

import yakuza_org;

#include <iostream>

int main() {
    YakuzaOrg tojo("Tojo Clan");

    tojo.addMember({ "Kiryu Kazuma",    "Former 4th Chairman aide", 98 });
    tojo.addMember({ "Majima Goro",     "Majima Family patriarch",  95 });
    tojo.addMember({ "Shimano Futoshi", "Shimano Family patriarch",  80 });
    tojo.addMember({ "Akiyama Shun",    "Sky Finance chairman",      72 });
    tojo.addMember({ "Nishikiyama Akira","Nishikiyama Family patriarch", 85 });

    tojo.showAll();

    Member top = tojo.strongest();
    std::cout << "=== Strongest Member ===" << std::endl;
    printMember(top);
    std::cout << std::endl;

    // formatStrength(98);  // compile error: module-private, not visible here

    return 0;
}
g++ -std=c++20 -fmodules-ts -x c++-module yakuza_org.cppm -c -o yakuza_org.o
g++ -std=c++20 -fmodules-ts -c yakuza_org.cpp -o yakuza_org_impl.o
g++ -std=c++20 -fmodules-ts main.cpp yakuza_org.o yakuza_org_impl.o -o yakuza_org_demo
./yakuza_org_demo
=== Tojo Clan Members ===
  [Legend] Kiryu Kazuma (Former 4th Chairman aide)  Strength: 98
  [Legend] Majima Goro (Majima Family patriarch)  Strength: 95
  [Executive] Shimano Futoshi (Shimano Family patriarch)  Strength: 80
  [Mid-level] Akiyama Shun (Sky Finance chairman)  Strength: 72
  [Executive] Nishikiyama Akira (Nishikiyama Family patriarch)  Strength: 85

=== Strongest Member ===
  [Legend] Kiryu Kazuma (Former 4th Chairman aide)  Strength: 98

Common Mistake 1: Mixing #include and module declarations incorrectly

Placing #include after export module can cause warnings or errors depending on the compiler. Use a global module fragment (module;) before the export module line to place legacy #include directives.

// NG (may error): #include placed after export module declaration
export module mylib;
#include <string>   // may cause issues on some compilers

OK: place #include in the global module fragment before the module declaration.

// OK:
module;             // global module fragment begins here
#include <string>
#include <vector>

export module mylib;

Common Mistake 2: Wrong compilation order causes "module not found"

The module interface unit must be compiled first to generate the BMI (Binary Module Interface). Compiling main.cpp before the interface unit produces a "module not found" error.

// NG: compiling main.cpp before the interface unit
// g++ -std=c++20 -fmodules-ts main.cpp -o demo  ← error: yakuza_org not found

OK: compile in the order — interface unit → implementation unit → consumer.

// OK: correct build order
// 1. Pre-compile the interface unit
// g++ -std=c++20 -fmodules-ts -x c++-module yakuza_org.cppm -c -o yakuza_org.o
// 2. Compile the implementation unit
// g++ -std=c++20 -fmodules-ts -c yakuza_org.cpp -o yakuza_org_impl.o
// 3. Compile and link main.cpp
// g++ -std=c++20 -fmodules-ts main.cpp yakuza_org.o yakuza_org_impl.o -o demo

Overview

C++20 modules replace the long-standing header-file and preprocessor text-inclusion mechanism with a new compilation unit management system. The traditional approach repeatedly expanded and parsed header text on each inclusion, inflating build times and carrying the risk of macro side-effects across files. Modules pre-compile the interface once into a BMI (Binary Module Interface) and reuse it, making them effective for shortening builds in large projects. Only declarations marked with export are visible outside the module; everything else is module-private, so encapsulation is enforced at the compiler level. A file with export module name; is the interface unit; a file with module name; is the implementation unit — a structure analogous to the traditional header/source split. Build flags vary by compiler: GCC uses -fmodules-ts, Clang uses -fmodules. The import <iostream>; syntax for importing standard library headers in module form is part of the specification, and as compiler support matures it is expected to eventually replace #include entirely.

If you find any errors or copyright issues, please .