Hubbry Logo
logo
Modules (C++)
Community hub

Modules (C++)

logo
0 subscribers
Be the first to start a discussion here.
Be the first to start a discussion here.
Contribute something to knowledge base
Hub AI

Modules (C++) AI simulator

(@Modules (C++)_simulator)

Modules (C++)

Modules in C++ are a feature added in C++20 implementing modular programming as a modern alternative to precompiled headers. A module in C++ comprises a single translation unit. Like header files and implementation files, a module can contain declarations and definitions, but differ from precompiled headers in that they do not require the preprocessor directive #include, but rather are accessed using the word import. A module must be declared using the word module to indicate that the translation unit is a module. A module, once compiled, is stored as a .pcm (precompiled module) file which acts very similar to a .pch (precompiled header) file. Module symbols and imports are resolved at the compilation stage, not the linking stage.

Modules most commonly have the extension .cppm (primarily common within Clang and GCC toolchains), though some alternative extensions include .ixx and .mxx (more common in Microsoft/MSVC toolchains), or even the traditional C++ extension .cpp.

Though the standard C language does not have modules, dialects of C allow for modules, such as Clang C. However, the syntax and semantics of Clang C modules differ from C++ modules significantly.

Prior to the conception of modules, C++ relied on the system of headers and source files. Precompiled headers existed and were similar to modules as snapshots of translation units easier to parse by the compiler and thus providing faster compilation, but did not have the same laws of encapsulation as modules. Modules were first proposed in 2012 for inclusion to C++14, but underwent extensive revisions and an entire redesign until the modern form was merged into C++20. An attempt to implement the feature in 2018 using Fortran existed.

Modules provide the benefits of precompiled headers with faster compilation than #included traditional headers, as well as faster processing during the linking phase. This is because modules are not handled by the C preprocessor during the preprocessing step, but rather directly by the compiler during compilation. Modules also reduce boilerplate by allowing code to be implemented in a single file, rather than being separated across a header file and source implementation. Separation of "interface file" and "implementation file" is still possible with modules, though modules provide a cleaner encapsulation of code. Separating code interface and source implementation, however, is necessary for benefiting from incremental builds. Modules eliminate the necessity of #include guards or #pragma once, as modules do not directly modify the source code. Modules, unlike headers, do not have to be processed or recompiled multiple times. However, similar to headers, any change in a module necessitates the recompilation of not only the module itself but also all its dependencies, and the dependencies of those dependencies, et cetera. Like headers, modules do not permit circular dependencies, and will not compile.

A module is imported using the keyword import followed by a module name, while a module is declared with export module followed by the name. All symbols within a module meant to be exposed publicly are marked export, and importing the module exposes all exported symbols to the translation unit. If a module is never imported, it will never be linked. Modules can export named symbols, but not macros which are consumed before compilation. Thus, modules prevent macros from unwantedly crossing translation units.

Unlike header inclusions, the order of import statements do not matter. A module can allow for transitive imports by marking an import with export import, which re-exports the imported module to a translation unit that imports the first module. Modules do not enforce any notion of namespaces, though by convention, modules should match namespaces and source file paths (for example, a namespaced class like wikipedia::project::util::ConfigLoader declared in module wikipedia.project.util.ConfigLoader residing in file wikipedia/project/util/ConfigLoader.cppm, similar to Java convention). using statements will only be applied in translation units if explicitly marked export, making it much less likely that using a using statement to bring symbols into the global namespace will cause name clashes across module translation units. This resolves pollution of using statements in headers, which due to textual inclusion of the header by an #include directive, will always result in using statements adding symbols into scope, even if unintentional.

The keyword export was first introduced in C++03 when "exported templates" were added to C++. These were later removed in C++11, due to very few compilers actually supporting the feature. The only compiler known to support exported templates was Comeau C/C++.

See all
User Avatar
No comments yet.