zurück zum Artikel

C++20: Module strukturieren

Rainer Grimm

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.

C++20: Module strukturieren

Ein Modul kann Module importieren und diese wieder zurĂŒckexportieren. Im folgenden Beispiel importiert das Modul math die Submodule math.math1 und math.math2.

// 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.

// mathModule1.ixx

export module math.math1; // (1)

export int add(int fir, int sec) { // (2)
return fir + sec;
}
// 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.

// 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)
C++20: Module strukturieren

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.

// 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
C++20: Module strukturieren

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.

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.

// 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.

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.

// 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
C++20: Module strukturieren

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.

Mehr Infos

C++-Schulungen

Ich freue mich darauf, meine C++-Schulung anzubieten zu können.

Online-Schulung (Deutsch):

PrÀsenz-Schulung (Deutsch):

Online Seminars (English):

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