C++20: Module strukturieren
Wenn das Modul gröĂer wird, sollte es in handliche Komponenten aufgeteilt werden. C++20 bietet dafĂŒr zwei Möglichkeiten an: Submodule und Partitionen.
Wenn das Modul gröĂer wird, sollte es in handliche Komponenten aufgeteilt werden. C++20 bietet dafĂŒr zwei Möglichkeiten an: Submodule und Partitionen. In diesem Artikel schaue ich mir beide Optionen genauer an.
Diesem Artikel möchte ich noch eine kurze Anmerkung vorausschicken. Der Einfachheit halber werde ich die Trennung von Module Interface Unit und Module Implementation Unit ignorieren. Das heiĂt, meine Module werden aus einer Datei bestehen. ZusĂ€tzlich werde ich keine NamensrĂ€ume verwenden. Ich habe beide Features bereits in dem vorherigen Artikel: "C++20: Module Interface Unit und Module Implemenation Unit [1]" vorgestellt.
Submodule sind einfach umzusetzen. Daher werde ich mit ihnen beginnen.
Submodule
Ein Modul kann Module importieren und diese wieder zurĂŒckexportieren. Im folgenden Beispiel importiert das Modul math
die Submodule math.math
1 und math.math2
.
- Modul
math
// mathModule.ixx
export module math;
export import math.math1;
export import math.math2;
Der Ausdruck export import math.math1
importiert das Modul math.math1
und exportiert es als Bestandteil des Moduls math
zurĂŒck.
Der VollstÀndigkeit halber sind hier die Module math.math1
und math.math2
. Ich verwende einen Punkt, um das Modul von seinen Submodulen zu trennen. Er ist aber nicht notwendig.
- Submodul
math.math1
// mathModule1.ixx
export module math.math1; // (1)
export int add(int fir, int sec) { // (2)
return fir + sec;
}
- Submodul
math.math2
// mathModule2.ixx
export module math.math2; // (1)
export { // (2)
int mul(int fir, int sec) {
return fir * sec;
}
}
Wenn du die Submodule sorgfÀltig studierst, wirst du einen kleinen Unterschied zwischen der export
-Anweisung (2) in den Modulen math.math1
und math.math2
feststellen. math.math1
verwendet einen export
-Spezifizierer und math.math2
ein sogenannte export
-Gruppe oder export
-Block.
Aus der Sicht der Anwender ist die Verwendung des Moduls math
einfach.
- Client-Programm
// mathModuleClient.cpp
import std.core;
import math;
int main() {
std::cout << std::endl;
std::cout << "add(3, 4): " << add(3, 4) << std::endl;
std::cout << "mul(3, 4): " << mul(3, 4) << std::endl;
}
Das Kompilieren, Linken und AusfĂŒhren des Programms lĂ€sst sich mit der Microsoft-Implementierung von Modulen wie gewohnt umsetzen:
cl.exe /std:c++latest /c /experimental:module mathModule1.ixx /EHsc /MD // (3)
cl.exe /std:c++latest /c /experimental:module mathModule2.ixx /EHsc /MD // (3)
cl.exe /std:c++latest /c /experimental:module mathModule.ixx /EHsc /MD // (3)
cl.exe /std:c++latest /experimental:module mathModuleClient.cpp mathModule1.obj mathModule2.obj mathModule.obj /EHsc /MD // (4)
Jeder Kompilierschritt (3) erzeugt zwei Artefakte: Die IFC-Datei (interface file) *.ifc
, die implizit in (4) verwendet wird, und die *.obj
-Datei, die explizit in (4) eingesetzt wird.
Ich habe bereits geschrieben, dass ein Submodul lediglich ein Modul ist. Jedes Submodul besitzt eine Modul-Deklaration (1). Konsequenterweise kann ich ein zweites Client-Programm implementieren, das nur das Modul math.math1
benötigt.
- Zweites Client-Programm
// mathModuleClient1.cpp
import std.core;
import math.math1;
int main() {
std::cout << std::endl;
std::cout << "add(3, 4): " << add(3, 4) << std::endl;
}
FĂŒr dieses Programm ist es ausreichend, das neue Client-Programm zu kompilieren und zu linken. Das existierende Modul math.math1
lĂ€sst sich direkt dafĂŒr verwenden:
cl.exe /std:c++latest /experimental:module mathModuleClient1.cpp mathModule1.obj /EHsc /MD
Die Trennung von Modulen in Module und Submodule ist ein einfaches Mittel fĂŒr Moduldesigner, Anwendern die Möglichkeit zu geben, die Module feingranular zu importieren. Diese Beobachtung gilt aber nicht fĂŒr Modul-Partitionen.
Modul-Partitionen
Ein Modul lĂ€sst sich in Partitionen aufteilen. Jede Partition besteht aus einem Module Interface Unit (partition interface file) und keiner oder mehrerer Module Implementation Units (C++20: Module Interface Unit und Module Implementation Unit [2]). Die Namen, die die Partitionen exportieren, werden durch das primĂ€re Module Interface (primary modul interface oder primare interface file) importiert und zurĂŒckexportiert. Der Name einer Partition muss mit dem Namen des Moduls beginnen. Eine Partition kann nicht selbststĂ€ndig existieren.
Leider ist die Beschreibung einer Modul-Partition deutlich komplizierter als ihre Umsetzung. In den folgenden Zeilen werde ich das Modul math
und seine Submodule math.math1
und math.math2
in Modul-Partitionen transformieren. Bei diesem einfachen Vorgang verwende ich die soeben eingefĂŒhrten Begriffe der Modul-Partition.
- Das primÀre Module Interface
mathPartition.ixx
// mathPartition.ixx
export module math; // (1)
export import :math1; // (2)
export import :math2; // (2)
Das primÀre Module Interface besteht aus der Modul-Deklaration (1). Es importiert und exportiert die Paritionen math1
und math2
mithilfe der Doppelpunkte zurĂŒck. Der Name der Partition muss mit dem Namen des Moduls beginnen. Konsequenterweise ist dieser daher im Ausdruck (2) nicht anzugeben.
- Modul-Partionen (
mathPartition1.ixx
undmathPartition2.ixx
)
export module math:math1; // (1)
export int add(int fir, int sec) {
return fir + sec;
}
// mathPartition2.ixx
export module math:math2; // (1)
export {
int mul(int fir, int sec) {
return fir * sec;
}
}
Analog zur Modul-Deklaration erklÀrt (1) eine sogenannte Module Interface Partition. Sie ist auch eine Module Interface Unit. Der Name math
steht fĂŒr den Namen des Moduls und die Namen math1
und math2
stehen fĂŒr die der Partition.
- Client-Programm
// mathModuleClient.cpp
import std.core;
import math;
int main() {
std::cout << std::endl;
std::cout << "add(3, 4): " << add(3, 4) << std::endl;
std::cout << "mul(3, 4): " << mul(3, 4) << std::endl;
}
Das Client-Programm ist identisch mit dem, das ich fĂŒr Submodule verwendet habe. Die gleiche Aussage gilt fĂŒr die Erzeugung des ausfĂŒhrbaren Programms:
cl.exe /std:c++latest /c /experimental:module mathPartition1.ixx /EHsc /MD
cl.exe /std:c++latest /c /experimental:module mathPartition2.ixx /EHsc /MD
cl.exe /std:c++latest /c /experimental:module mathPartition.ixx /EHsc /MD
cl.exe /std:c++latest /experimental:module mathModuleClient.cpp mathPartition1.obj mathPartition2.obj mathPartition.obj /EHsc /MD
Wie geht's weiter?
Module in C++20 haben noch mehr zu bieten. So fĂŒhren sie zum Beispiel "Header Units" ein und unterscheiden zwischen dem globalen und privaten Modul-Fragment. Zuletzt möchte ich auf das Linken des Programms eingehen.
C++-Schulungen
Ich freue mich darauf, meine C++-Schulung anzubieten zu können.
Online-Schulung (Deutsch):
PrÀsenz-Schulung (Deutsch):
Online Seminars (English):
- C++11 and C+14: 13 July 2020 - 17 July 2020 (5 * 1/2 day) [5]
- Clean Code with modern C++: 03 August 2020 - 07 August 2020 (5 * 1/2 day) [6]
Mehr Informationen zu meinen Schulungen gibt es auf meiner deutschen (www.ModernesCpp.de [7]) oder englischen Schulungsseite (www.ModerenesCpp.net [8]).
Ich habe die Preise meine Online-Schulungen wĂ€hrend der Corona-Krise deutlich reduziert. Wem der Preis noch zu hoch ist, der kann direkt mit mir (schulung@ModernesCpp.de [9]) Kontakt aufnehmen. Dies Angebot gilt natĂŒrlich auch fĂŒr Firmen.
( [10])
URL dieses Artikels:
https://www.heise.de/-4770234
Links in diesem Artikel:
[1] https://heise.de/-4727382
[2] https://heise.de/-4727382
[3] https://www.modernescpp.de/index.php/c/2-c/26-embedded-programmierung-mit-modernem-c-online
[4] https://www.modernescpp.de/index.php/c/2-c/24-embedded-programmierung-mit-modernem-c20200306121340
[5] https://www.modernescpp.net/index.php/c/2-c/30-c-11-and-c-14
[6] https://www.modernescpp.net/index.php/c/2-c/28-clean-code-with-modern-c
[7] https://www.modernescpp.de/
[8] https://www.modernescpp.net/
[9] mailto:schulung@ModernesCpp.de
[10] mailto:rainer@grimm-jaud.de
Copyright © 2020 Heise Medien