More Details to Modules
My last post gave you an introduction to modules in C++20. This post shows how to use existing modules.
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 slightly shorter. As promised in my last post, let me show you the program’s output.
Using a Standard Module
Essentially, neither the module interface nor the implementation unit changed in 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; }
Modernes C++ Mentoring
Do you want to stay informed: Subscribe.
Thanks to the module std.core, I can show the result of the addition.
Using the header <iostream> would also be possible. Of course, I hear your question about which modules are available. Here is what I have from the “Using C++ Modules in Visual Studio 2017” post from the Microsoft C++ team blog.
C++ Modules in Visual Studio 2017
std.regex
provides the content of the header<regex>
std.filesystem
provides the content of the header<experimental/filesystem>
std.memory
provides the content of the header<memory>
std.threading
provides 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 a little more complicated than 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 declared with export are exported. If not, the name is not visible outside the module and has module linkage. This holds in particular for the function add but not for the 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 pretty comfortable in my case. Instead of using the four headers in the line (1), I’m okay with a simple import std.core in line (2). That was it. Here is the output of the program.
Now, to the question: What happens if I add the function add in line (3). To recap, add is not exported and has module linkage.
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()
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();
}
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();
}
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 is 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 fine to use the exported and non-exported names in the module math. But the module math.core is not exported. Only a client using 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 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 imports 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, Jozo Leko, John Breland, Venkat Nandam, Jose Francisco, Douglas Tinkham, Kuchlong Kuchlong, Robert Blanch, Truels Wissneth, 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, Stephen Kelley, Kyle Dean, Tusar Palauri, Juan Dent, George Liao, Daniel Ceperley, Jon T Hess, Stephen Totten, Wolfgang Fütterer, Matthias Grün, Phillip Diekmann, Ben Atakora, Ann Shatoff, Rob North, Bhavith C Achar, Marco Parri Empoli, Philipp Lenk, Charles-Jianye Chen, Keith Jeffery,and Matt Godbolt.
Thanks, in particular, to Jon Hess, Lakshman, Christian Wittenhorst, Sherhy Pyton, Dendi Suhubdy, Sudhakar Belagurusamy, Richard Sargeant, Rusty Fleming, John Nebel, Mipko, Alicja Kaminska, Slavko Radman, and David Poole.
My special thanks to Embarcadero | |
My special thanks to PVS-Studio | |
My special thanks to Tipi.build | |
My special thanks to Take Up Code | |
My special thanks to SHAVEDYAKS |
Modernes C++ GmbH
Modernes C++ Mentoring (English)
Rainer Grimm
Yalovastraße 20
72108 Rottenburg
Mail: schulung@ModernesCpp.de
Mentoring: www.ModernesCpp.org
Modernes C++ Mentoring,
Leave a Reply
Want to join the discussion?Feel free to contribute!