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.

 

Rainer D 6 P2 540x540Modernes C++ Mentoring

Stay informed about my mentoring programs.

 

 

Subscribe via E-Mail.

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: Matt Braun, Roman Postanciuc, Tobias Zindl, G Prvulovic, Reinhold Dröge, Abernitzke, Frank Grimm, Sakib, Broeserl, António Pina, Sergey Agafyin, Андрей Бурмистров, Jake, GS, Lawton Shoemake, Animus24, Jozo Leko, John Breland, Venkat Nandam, Jose Francisco, Douglas Tinkham, Kuchlong Kuchlong, Robert Blanch, Truels Wissneth, Kris Kafka, Mario Luoni, Friedrich Huber, lennonli, Pramod Tikare Muralidhara, Peter Ware, Daniel Hufschläger, Alessandro Pezzato, Bob Perry, Satish Vangipuram, Andi Ireland, Richard Ohnemus, Michael Dunsky, Leo Goodstadt, John Wiederhirn, Yacob Cohen-Arazi, Florian Tischler, Robin Furness, Michael Young, Holger Detering, Bernd Mühlhaus, Matthieu Bolt, Stephen Kelley, Kyle Dean, Tusar Palauri, Dmitry Farberov, Juan Dent, George Liao, Daniel Ceperley, Jon T Hess, Stephen Totten, Wolfgang Fütterer, Matthias Grün, Phillip Diekmann, Ben Atakora, Ann Shatoff, and Dominik Vošček.

 

Thanks, in particular, to Jon Hess, Lakshman, Christian Wittenhorst, Sherhy Pyton, Dendi Suhubdy, Sudhakar Belagurusamy, Richard Sargeant, Rusty Fleming, John Nebel, Mipko, Alicja Kaminska, and Slavko Radman.

 

 

My special thanks to Embarcadero CBUIDER STUDIO FINAL ICONS 1024 Small

 

My special thanks to PVS-Studio PVC Logo

 

My special thanks to Tipi.build tipi.build logo

Seminars

I'm happy to give online seminars or face-to-face seminars worldwide. Please call me if you have any questions.

Bookable (Online)

German

Standard Seminars (English/German)

Here is a compilation of my standard seminars. These seminars are only meant to give you a first orientation.

  • C++ - The Core Language
  • C++ - The Standard Library
  • C++ - Compact
  • C++11 and C++14
  • Concurrency with Modern C++
  • Design Pattern and Architectural Pattern with C++
  • Embedded Programming with Modern C++
  • Generic Programming (Templates) with C++

New

  • Clean Code with Modern C++
  • C++20

Contact Me

Modernes C++,

RainerGrimmDunkelBlauSmall

Tags: Modules

Mentoring

Stay Informed about my Mentoring

 

English Books

Course: Modern C++ Concurrency in Practice

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

Course: Embedded Programming with Modern C++

Course: Generic Programming (Templates)

Course: C++ Fundamentals for Professionals

Interactive Course: The All-in-One Guide to C++20

Subscribe to the newsletter (+ pdf bundle)

All tags

Blog archive

Source Code

Visitors

Today 5638

Yesterday 7929

Week 21455

Month 165626

All 11646780

Currently are 210 guests and no members online

Kubik-Rubik Joomla! Extensions

Latest comments