C++20: More Details to Modules

 My last post gave you the introduction to modules in C++20. This post shows, how to use existing modules.

boxes 2624231 1280

Before I begin this post, let me shortly sum up, where we ended in my first post to modules.

A Short Recap

I created a module math1, which consisted of a module interface unit and a module implementation unit and a client, which used it. Here are the three source files.

Module Interface Unit

// math1.cppm

export module math1;

export int add(int fir, int sec);

Module Implementation Unit

// math1.cpp

module math1;

int add(int fir, int sec){
    return fir + sec;
}

Client

// main1.cpp

import math1;

int main(){
   
   add(2000, 20);
   
}

I compiled the program with a current clang and cl.exe compiler. From now on, I will stick with the cl.exe compiler because the compile line is a little bit shorter. As promised in my last post, let me show you the output of the program.

Using a Standard Module

Essential, neither the module interface unit nor the module implementation unit changed in the module math2.

Module Interface Unit

// math2.cppm

export module math2;

export int add(int fir, int sec);

Module Implementation Unit

// math2.cpp

module math2;

int add(int fir, int sec){
    return fir + sec;
}

Client

// main2.cpp

//#include <iostream>

import std.core;

import math2;

int main(){
	
    std::cout << std::endl;
   
    std::cout << "add(2000, 20): " << add(2000, 20) << std::endl;
   
}

 

Thanks to the module std.core, I can show the result of the addition.

math2

Using the header <iostream> would also be possible. Of course, I hear your question, which modules are available. Here is what I have from the post "Using C++ Modules in Visual Studio 2017" from the Microsoft C++ team blog.

C++ Modules in Visual Studio 2017

  • std.regex provides the content of header <regex>
  • std.filesystem provides the content of header <experimental/filesystem>
  • std.memory provides the content of header <memory>
  • std.threading provodes the contents of headers <atomic>, <condition_variable>, <future>, <mutex>, <shared_mutex>, <thread>
  • std.core provides everything else in the C++ Standard Library

Modules provide a higher abstraction than headers. This makes it quite comfortable to use them. Additionally, you can specify, which name of a module should be exported or not.

Export versus Non-Export

The next module math3 is little more complicated as the previous one. Here is the interface.

Module Interface Unit

 

// math3.cppm

import std.core;

export module math3;

int add(int fir, int sec);

export int mult(int fir, int sec);

export void doTheMath();

 

The module interface unit contains the exporting module declaration: export module math3;. The module declaration starts the so-called module purview. Only names after the module purview, which are declared with export are exported. If not, the name is not visible outside the module and has, therefore, module linkage. This holds in particular for the function add but not for the functions mult and doTheMath.

Module Implementation Unit

// math3.cpp

module math3;

int add(int fir, int sec){
    return fir + sec;
}

int mult(int fir, int sec){
    return fir * sec;
}

void doTheMath(){
	std::cout << "add(2000, 20): " << add(2000, 20) << std::endl;
}

 

There is nothing to add to the module implementation unit. The main program is more interesting.

Client

// main3.cpp

// #include <iostream>    // (1)
// #include <numeric>     // (1)
// #include <string>      // (1)
// #include <vector>      // (1)
import std.core;          // (2)

import math3;

int main(){
	
    std::cout << std::endl;
   
    // std::cout << "add(2000, 20): " << add(2000, 20) << std::endl;   // (3)
	
    std::vector<int> myVec = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
	
    std::string doc = "std::accumulate(myVec.begin(), myVec.end(), mult): "; 
    auto prod = std::accumulate(myVec.begin(), myVec.end(), 1, mult);
	
    std::cout << doc << prod << std::endl; 
	
    doTheMath();
	
}

 

You see, modules are quite comfortable in my case. Instead of using the four headers in the lines (1),  I'm okay with a simple import std.core in line (2). That was it. Here is the output of the program.

 math3

Now, to the question: What is happening if I use the function add in the line (3). To recap, add is not exported and has, therefore, module linkage. 

math3Add

The compiler complains that the function add is used in the main program, but the name add is not visible.

Further Details

First, you can export in various ways.

Export

Exporting names with export specifiers such as in math3.cppm is tedious.

Export Specifier

// math3.cppm

import std.core;

export module math3;

int add(int fir, int sec);

export int mult(int fir, int sec);

export void doTheMath()
 
Instead of an export specifier, you can use an exported group.

Exported Group

// math3.cppm

import std.core;

export module math3;

int add(int fir, int sec);

export {

int
mult(int fir, int sec); void doTheMath();

}
 
The third variation is it to use an exported namespace.

Exported Namespace

// math3.cppm

import std.core;

export module math3;

namespace math3 {

int add(int fir, int sec);

}

export namespace math3 {

int
mult(int fir, int sec); void doTheMath();

}
 
All three variations are semantically equivalent.
 

It may also be quite comfortable to re-export a module

Re-Export a Module

Sometimes, you want to export something which you imported from another module. If you don't export the imported module, the imported module has consequently module linkage and its names are not visible outside the module. Here is a concrete example.

Visible versus Invisible

Imagine, I want to import and use the module math.core and math.core2 in a new module math. Here are the module interface unit of math.core and math.core2.

  • Re-exported modules

 

// module interface unit of math.core

export math.core

export int mult(int fir, int sec); 

 

// module interface unit of math.core2

export math.core2

export int add(int fir, int sec); 

Next, here is the new module math.

  • The new module math

 

// module interface unit of math

export module math;

import math.core;           // not exported with mult
export import math.core2;   // exported with add


// module implementation unit of math

mult(1100, 2);             // fine
add(2000, 20);             // fine

As you can see, it's totally fine to use the exported and non-exported names in the module math. But the module math.core is not exported. Only a client, which uses the module math, will see the difference.

  • Client
// Client

import math

mult(1100, 2);             // ERROR
add(2000, 20);             // fine

The function mult has module linkage and is, therefore, not visible outside the module. Only the function add is visible.

Repackage Modules

There is a comfortable way to repackage modules. Just put them in an exported group.

export module math;

export{

    import math.core;
    import math.core2;
    import math.basics;
	
}

 

This makes all names visible for a client which import the module math.

What's next?

With my next post, I begin the last main topic of the C++ core guidelines: rules to the standard library. Believe it or not, many professional C++ developers don't use the standard template library (STL). This holds, in particular, true for the algorithms of the STL.

 

 

Thanks a lot to my Patreon Supporters: Paul Baxter,  Meeting C++, Matt Braun, Avi Lachmish, Roman Postanciuc, Venkata Ramesh Gudpati, Tobias Zindl, Marko, Ramesh Jangama, G Prvulovic, Reiner Eiteljörge, Benjamin Huth, Reinhold Dröge, Timo, Abernitzke, Richard Ohnemus, and Frank Grimm.

Thanks in particular to:  TakeUpCode 450 60     crp4

 

Get your e-book at Leanpub:

The C++ Standard Library

 

Concurrency With Modern C++

 

Get Both as one Bundle

cover   ConcurrencyCoverFrame   bundle
With C++11, C++14, and C++17 we got a lot of new C++ libraries. In addition, the existing ones are greatly improved. The key idea of my book is to give you the necessary information to the current C++ libraries in about 200 pages.  

C++11 is the first C++ standard that deals with concurrency. The story goes on with C++17 and will continue with C++20.

I'll give you a detailed insight in the current and the upcoming concurrency in C++. This insight includes the theory and a lot of practice with more the 100 source files.

 

Get my books "The C++ Standard Library" (including C++17) and "Concurrency with Modern C++" in a bundle.

In sum, you get more than 600 pages full of modern C++ and more than 100 source files presenting concurrency in practice.

 

Get your interactive course

 

Modern C++ Concurrency in Practice

C++ Standard Library including C++14 & C++17

educative CLibrary

Based on my book "Concurrency with Modern C++" educative.io created an interactive course.

What's Inside?

  • 140 lessons
  • 110 code playgrounds => Runs in the browser
  • 78 code snippets
  • 55 illustrations

Based on my book "The C++ Standard Library" educative.io created an interactive course.

What's Inside?

  • 149 lessons
  • 111 code playgrounds => Runs in the browser
  • 164 code snippets
  • 25 illustrations

Add comment


Subscribe to the newsletter (+ pdf bundle)

Blog archive

Source Code

Visitors

Today 1668

All 2308200

Currently are 121 guests and no members online

Kubik-Rubik Joomla! Extensions

Latest comments