mutlugazete.com

Understanding C++20 Modules: A Comprehensive Guide

Written on

Chapter 1: Introduction to C++20 Modules

In modern C++, we typically include libraries using the #include directive, which involves transferring code from header files to source files. While this method is prevalent, it has significant drawbacks:

  • Multiple Inclusions: A source file may be included multiple times in the same translation unit. To mitigate this, developers often use #pragma once or #ifndef.
  • Code Duplication: This can lead to increased compilation times. Any changes to a header file necessitate recompiling all files that include it.
  • Order of Inclusions: The sequence of #include statements can sometimes result in unexpected compilation errors.

C++20 introduces a novel alternative to the traditional #include directive: modules. Let's explore the concept of modules in depth.

Section 1.1: Module Units

A C++ module comprises one or more translation units (TUs) that incorporate specific keywords for declaration. These translation units are termed module units. Non-module units belong to an anonymous global module that contains standard non-module code and lacks an interface.

Subsection 1.1.1: Global Module Fragment

Module units can initiate with a global module fragment, which facilitates direct utilization of existing code when importing headers is not feasible, particularly when preprocessor macros are involved.

For instance:

module;

#ifdef Say

void hello();

#endif

export module Foo;

// purview

void world();

It's crucial to note that if a module features a global module fragment, its initial declaration must be module;. Any deviation will trigger an error.

Subsection 1.1.2: Purview

Purview refers to the entire scope of a module, extending from the module declaration to the end of the translation unit. For instance:

void hello(); // <- Not within the purview of the Foo module

export module Foo; // <- Within the purview of the Foo module

void world();

export void GetData();

Subsection 1.1.3: Private Module Fragment

The main module interface unit can incorporate a private module fragment as a suffix. This fragment can only exist in the primary module interface unit, ensuring that the module's interface and implementation remain encapsulated within a single translation unit.

For example, if we want to define a Shape class and compute its area, we can expose only the necessary interface while keeping implementation details hidden:

export module Shape;

export class Shape {

public:

virtual double CalculateArea() = 0;

};

export { std::shared_ptr CreateRectangle(double length, double width); }

module :private; // This is where it appears

class Rectangle : public Shape {

private:

double length;

double width;

public:

Rectangle(double l, double w) : length(l), width(w) {}

double CalculateArea() override { return length * width; }

};

std::shared_ptr CreateRectangle(double length, double width) {

return std::make_shared<Rectangle>(length, width);

}

However, it's important to recognize that support for private module fragments may vary across compilers. For example, GCC version 13 currently does not support them, while Clang version 16 does.

Chapter 2: Utilizing Modules

Section 2.1: Creating a Module

Creating a module resembles defining a header file, typically with a .cppm extension. The export and module keywords precede the module name to create an exportable module:

// foo.cppm

export module foo;

// main.cc

import foo;

The export keyword can be used for various entities, including functions, classes, and variables, with two common syntax forms available.

Section 2.2: Exporting Entities

A key question arises: what can be exported? Variables, classes, structs, functions, namespaces, template functions/classes, and concepts are exportable. However, internal linkage entities, such as static variables and functions in anonymous namespaces, cannot be exported.

For example:

export static constexpr double PI = 3.14; // Error: Cannot be exported

Export declarations must occur at the namespace level.

Section 2.3: Importing Modules

When it comes to importing, certain rules apply:

  • A module cannot import itself.
  • In a module unit, all imports must precede any declarations.
  • Only global-scope imports are permitted.

Section 2.4: Including in Modules

To include files in a module, you can replace #include with import:

export module foo;

import <iostream>;

For compiling with GCC-13, you may need to compile system headers explicitly.

Chapter 3: Module Decomposition

When breaking down a large module into smaller components, two methods can be employed: module partitions and submodules.

Section 3.1: Module Partitions

This allows for splitting a module into multiple files without user visibility. For instance:

export module shape;

export import :circle;

export import :rectangle;

Section 3.2: Submodules

Submodules allow for dividing a main module into various nested submodules. The main module's name must precede submodule imports.

Chapter 4: Interface and Implementation

Even with modules, you can still adhere to the traditional code separation approach. For example, to define a shape and its drawing functionality:

export module shape;

export class Shape {

public:

Shape();

void Draw();

};

// Implementation

import shape;

import <iostream>;

Shape::Shape() {}

void Shape::Draw() { std::cout << "draw a shape" << std::endl; }

References

This video discusses the packaging and binary redistribution of C++20 modules, providing insights into their structure and benefits.

In this video, Cameron DaCamara shares practical applications of C++20 modules and the future of tooling surrounding them.

Share the page:

Twitter Facebook Reddit LinkIn

-----------------------

Recent Post:

From Frustration to Viral: My Journey of Writing Truths

Discover how anger over a health issue led to my first viral article, shedding light on misleading products and inspiring others.

Understanding the Transactions Business Model: Insights for Product Managers

Explore the Transactions Business Model, its mechanisms, revenue generation, and key metrics for success.

The 5 Habits Sabotaging Your Sex Life and How to Avoid Them

Discover five common habits that can negatively affect your sex life and learn how to avoid them for better intimacy.

Creative Expression and the Impact of Criticism

Exploring how criticism shapes creativity and self-acceptance in life.

Influencer Insights: Why Top Performers May Mislead You

Explore why not all high achievers offer the best advice, especially in fitness and health, as we dissect the influencer phenomenon.

The Unexpected Mobility of Barnacles: A Closer Look

Discover the surprising mobility of barnacles and their feeding strategies in relation to sea turtles.

Unlocking Emotional Intelligence: A Path to Personal and Professional Growth

Explore emotional intelligence's significance and development in personal and professional realms.

Shifting Perspectives on Inflation: A Cautious Optimism Emerges

A new wave of consumer confidence suggests optimism about inflation, though caution remains necessary as challenges linger.