Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.syntblaze.com/llms.txt

Use this file to discover all available pages before exploring further.

A private module fragment is a designated section within a C++20 primary module interface unit that encapsulates internal declarations and definitions, rendering them completely unreachable to any importing translation unit. It allows a single-file module to strictly separate its public interface from its private implementation details without requiring a distinct module implementation file.

Syntax and Placement

The private module fragment is initiated by the module :private; directive.
export module module_name;

// [Module Purview]
// Exported and non-exported interface declarations go here.

module :private;

// [Private Module Fragment]
// Imports specific to the private fragment (must be first).
// Internal definitions and declarations go here.

Structural Constraints

The C++ standard enforces strict architectural rules regarding the placement and usage of the private module fragment:
  1. Primary Interface Only: It can only appear within a primary module interface unit (export module M;). It is ill-formed to include a private module fragment in a module implementation unit (module M;) or a module partition (export module M:part; or module M:part;).
  2. Single Translation Unit Restriction: If a primary module interface contains a module :private; fragment, the C++ standard completely forbids the existence of any module implementation units or module partitions for that module. A module utilizing a private module fragment must be the only translation unit for that entire module.
  3. Terminal Section: The module :private; directive must be the final structural marker in the file. Everything from the directive to the end of the translation unit belongs to the private fragment.
  4. Singularity: A module unit may contain at most one private module fragment.
  5. Import Placement: import declarations are permitted inside the private module fragment. However, they must appear at the very beginning of the fragment, immediately following the module :private; directive and preceding all other non-import declarations within the fragment’s declaration sequence.

Reachability vs. Visibility

To understand the technical mechanism of the private module fragment, it is necessary to distinguish between visibility (name lookup) and reachability (semantic availability) in C++20.
  • Non-exported Module Purview: Entities declared in the module purview without the export keyword are not visible to importers, but they remain reachable. If an exported function returns a non-exported type via auto, the importing unit can still instantiate and interact with that type’s definition.
  • Private Module Fragment: Entities declared after module :private; are neither visible nor reachable. The compiler guarantees that no semantic information from this fragment leaks into the Built Module Interface (BMI). If an exported entity attempts to expose a type defined in the private fragment, the program is ill-formed.

Syntax Visualization

The following code block demonstrates the structural boundaries and constraints enforced by the private module fragment:
module; // Optional global module fragment

export module Networking; // Primary module interface unit

// --- MODULE PURVIEW (Reachable) 

export class Socket {
public:
    Socket();
    ~Socket();
    void connect();
private:
    struct SocketState; // Forward declaration
    SocketState* state; // Pointer to incomplete type is allowed
};

// --- PRIVATE MODULE FRAGMENT (Unreachable) 
module :private; 

// Imports are allowed here, provided they precede all other declarations
import <iostream>;

// The definition of SocketState is completely hidden from importers.
// It cannot be reached, even implicitly.
struct Socket::SocketState {
    int file_descriptor{-1};
    bool is_active{false};
};

Socket::Socket() : state(new SocketState{}) {}
Socket::~Socket() { delete state; }
void Socket::connect() {
    state->is_active = true;
    std::cout << "Socket connected.\n";
}

Compilation Model Impact

Because the private module fragment is guaranteed to be unreachable by importers, the compiler strips this section when generating the Built Module Interface (BMI) file (e.g., .pcm or .ifc). Consequently, modifications made exclusively within the private module fragment alter only the generated object file (.o/.obj). They do not alter the BMI, meaning downstream translation units that import the module do not require recompilation.
Master C++ with Deep Grasping Methodology!Learn More