5.2.32 · D1C++ Programming

Foundations — Modules (C++20) — concept and syntax

1,496 words7 min readBack to topic

Before you can read a single line of the parent note, you must already own a small pile of ideas: what a source file is, what compiling even does, what a macro is, what "a name is visible" means. The parent note quietly assumes all of them. This page builds every one from the ground up, in the order they depend on each other.


1. The source file — a page of text

Figure — Modules (C++20) — concept and syntax

Look at the figure. On the left is one text file. The compiler cannot run text — it must first translate it into machine instructions. That translation is the next idea.


2. Compiling — turning text into a machine part


3. Translation unit — what the compiler actually chews

Figure — Modules (C++20) — concept and syntax

In the figure, the file main.cpp on its own is small, but after #include pastes header text in, the translation unit balloons. That ballooning — the same header text copied into hundreds of TUs — is problem #1 the parent note lists ("slow builds"). This idea is so central it has its own vault note: Translation Units and Linkage.


4. The preprocessor and #include — the copy-paste machine

Because #include is paste, two files that both include the same header get two copies of every declaration — which is why the old world needed include guards (a #ifndef trick to skip the second paste). Modules delete this whole headache; that is the parent's "No guards needed" row.


5. #define and macros — the leaky part

Modules do not carry macros across import. That single fact is why the parent celebrates "Macros do not leak." You must know what a macro is to see why not-leaking is a win.


6. Names, visibility, and scope

Figure — Modules (C++20) — concept and syntax

The figure shows three nested visibility rings. This ring picture is exactly what the parent's biggest mistake callout is about: export and public are different rings.

  • public / private — an inner ring: which class members other code may touch.
  • export — an outer ring: which file-level names cross the module boundary to importers.

A private member of an exported class is exported-as-a-class but still privately sealed — two independent rings, both must open for you to reach it.


7. export and import — the new keywords

Everything after export module Name; is the named-module region, where #include is forbidden — the reason for the quarantine zone before it.


8. Why any of this — the build-speed payoff


Prerequisite map

Source file = text

Compiling = text to machine code

Translation unit = one lump

Preprocessor and include = paste

Macros define = blind replace

Names and visibility

export and import

Build speed pain

Modules C++20

Every arrow says "you need the left idea before the right idea makes sense." All roads feed the parent: Modules (C++20).


Equipment checklist

Test yourself — say the answer aloud, then reveal.

A source file is
a plain text file of C++ instructions, nothing magic.
Compiling means
a compiler reads one source file and produces machine code (an object file).
Parsing is
the reading/understanding step inside compiling — the slow part modules do once.
A translation unit is
one source file plus everything textually pasted into it, compiled as one lump.
#include <x> does
pastes the entire text of file x right there, before compiling.
A macro (#define) is
a blind text-replacement rule the preprocessor applies everywhere, ignoring scope.
Why macros are dangerous
they leak across every file that includes the header and respect no boundaries.
:: means
scope resolution — "which box (namespace or class) this name lives in."
public/private control
which class members outside code may touch (inner ring).
export controls
which file-level names cross the module boundary to importers (outer ring).
import math; does
reads module math's compiled interface and brings in its exported names — link, not paste.
The : in export module m:p; marks
a partition, a sub-piece of module m.
Why modules build faster
the interface is parsed/compiled once into a binary and reused, not re-parsed everywhere.