Open In App

Modules in C++ 20

In C++20, the concept of modules was introduced to improve the efficiency of the compilation process and provide better organization and encapsulation of code. Modules allow developers to divide their code into separate components, each with its own interface and implementation, and import them as needed. This article will explain the concept of modules in C++20, provide examples, and demonstrate the approach to working with modules.

Need for Modules

Module Units

A module unit is a source file meant to contain a module declaration. Different types of module units in C++20 modules are:



Syntax

Module Declaration

To declare a module, you need to create a module interface unit, which is a separate file with the ‘.ixx’, ‘.cppm’, or ‘.mxx’ extensions. Inside this file, you declare the module using the module keyword followed by the module name.

// module_name.ixx - Module interface unit
module module_name; // declares a module named "module_name"
export module module_name; // declares and exports a module named "module_name"
module A.B; // declares a submodule named "B" within module "A"
export module A.B // declares and exports a submodule named "B" within module "A"

Exporting Declarations

Within a module, we can define declarations (e.g., variables, functions, classes) that we want to export to other modules using the ‘export’ keyword. Exported declarations become part of the module’s interface and can be imported by other modules.



export module module_name; // module declaration
export data_type variable_name; // export declaration
export return_type function_name(); // export declaration

Example




// math.cppm - Module implementation file
  
// module declaration for math module
  
export module math;
  
// function to add two integers
export int add(int a, int b) { return a + b; }
  
// function to multiply two integers
export int multiply(int a, int b) { return a * b; }

Explanation

In the above example, we have a module named math implemented in the file ‘math.cppm’. The export module math; statement declares the module named “math”. The export keyword indicates that the module is part of the interface and can be imported by other modules.

Importing Modules and Declarations

To use declarations from other modules, we need to import them. The import keyword is used to import a module or a specific declaration from a module.

module module_name;
// imports the entire module "othermodule" into the current module "mymodule"
import othermodule;
// imports the declaration of the function "function_name" from the module "othermodule" into the current module "mymodule"
import othermodule.function_name;

Example




// main.cpp
  
// importing the math module
  
import math;
  
#include <iostream>
int main()
{
    // calling the add function from the math module
    int result = add(3, 5);
  
    // calling the multiply function from the math module
    result = multiply(2, 4);
    return 0;
}

Explanation

In the main.cpp file, we import the math module declared in the previous example using the import keyword. This allows us to access the functions add and multiply defined in the math module. We can use these functions as if they were defined in the current file.

Building and Compiling Modules

To compile and build modules, you’ll need a C++20-compliant compiler. To compile and run the code, you’ll need a C++20-compliant compiler that supports modules. The specific steps depend on the compiler you’re using. Here’s an example using ‘g++’ :




g++ -std=c++20 -c math.ixx   // Compile the module interface unit
g++ -std=c++20 -c math_extra.cpp   // Compile a partition (implementation unit)
g++ -std=c++20 main.cpp math.ixx math_extra.o -o main   // Link the modules and build the executable

Output

Addition Result: 8
Multiplication Result:8

These are the basic syntax elements of modules in C++20. With modules, you can better organize and encapsulate your code, improve compilation times, and enhance code reusability and maintainability.

When a header file is included using the #include directive, the preprocessing macros defined within the translation unit can affect the processing of the included header file. However, when using modules, the processing of preprocessing macros defined within the translation unit does not directly affect the processing of included headers within the module. Here, the Global module fragment can be useful.

Global module fragment

A global module fragment can be placed at the beginning of module units. The global module fragment allows us to include header files when they can not be imported directly, particularly when the header file relies on preprocessing macros for configuration.

module;
// Preprocessing directives (optional)
module-declaration;

Example




// module_a_fragment.cppm (Global module fragment)
module;
  
// Preprocessing directives (optional)
#define MY_MACRO
  
// End of global module fragment
  
module A;
  
import<iostream>;
  
// Example function
export void demo_func() { 
  cout << "Hello from module A!\n";
}




// main.cpp (not a module unit)
import A;
  
int main()
{
    demo_func(); // Call function from module A
    return 0;
}

Output

Hello from module A!

Private module fragment

Primary module interface unit can be suffixed by a private module fragment. Private module fragment represents a module as a single translation unit that restricts the accessibility of its contents to importers.

// Public declarations accessible to importers
module ModuleName;
// Private declarations not accessible to importers
module ModuleName : private;
// End of the private module fragment

Module partitions

A module can be divided in module partition units which starts with a colon :. These partitions are only accessible by the main module.

export module A:B; // Declares a module interface unit for module 'A', partition ':B'.

Conclusion

This article demonstrates how to create and use modules in C++20. The module interface and implementation are separated, allowing for better organization and encapsulation of code. The imported module’s functions can be used in other files, enhancing code reusability and maintainability.

Related Article:


Article Tags :
C++