Sdílet prostřednictvím


Kurz pojmenovaných modulů (C++)

Tento kurz se týká vytváření modulů C++20. Moduly nahrazují soubory hlaviček. Dozvíte se, jak moduly vylepšují soubory hlaviček.

V tomto kurzu se naučíte:

  • Vytvoření a import modulu
  • Vytvoření jednotky rozhraní primárního modulu
  • Vytvoření souboru oddílu modulu
  • Vytvoření souboru implementace jednotek modulu

Požadavky

Tento kurz vyžaduje Visual Studio 2022 17.1.0 nebo novější.

Při práci na příkladu kódu v tomto kurzu se můžou zobrazit chyby IntelliSense. Práce na modulu IntelliSense dohání kompilátor. Chyby IntelliSense je možné ignorovat a nezabrání sestavení příkladu kódu. Pokud chcete sledovat průběh práce IntelliSense, podívejte se na tento problém.

Co jsou moduly C++

Soubory hlaviček jsou způsob sdílení deklarací a definic mezi zdrojovými soubory v jazyce C++. Soubory hlaviček jsou křehké a obtížně se vytváří. Můžou se kompilovat jinak v závislosti na pořadí, ve které je zahrnete, nebo na makrech, která jsou nebo nejsou definována. Můžou zpomalit dobu kompilace, protože se znovu zpracovávají pro každý zdrojový soubor, který je obsahuje.

C++20 představuje moderní přístup ke komponentizaci programů C++: modulů.

Podobně jako soubory hlaviček umožňují moduly sdílet deklarace a definice napříč zdrojovými soubory. Na rozdíl od souborů hlaviček ale moduly nevracely definice maker ani podrobnosti privátní implementace.

Moduly se snadněji vytváří, protože jejich sémantika se nemění kvůli definicím maker nebo k importu, pořadí importů atd. Usnadňují také kontrolu nad tím, co je viditelné pro uživatele.

Moduly poskytují dodatečné bezpečnostní záruky, že soubory hlaviček ne. Kompilátor a linker spolupracují, aby se zabránilo možným problémům se kolizemi názvů, a poskytuje silnější záruky jednoho pravidla definice (ODR).

Model silného vlastnictví zabraňuje konfliktům mezi názvy v době propojení, protože linker připojí exportované názvy k modulu, který je exportuje. Tento model umožňuje kompilátoru jazyka Microsoft Visual C++ zabránit nedefinovanému chování způsobenému propojením různých modulů, které hlásí podobné názvy ve stejném programu. Další informace naleznete v tématu Silné vlastnictví.

Modul se skládá z jednoho nebo více souborů zdrojového kódu zkompilovaných do binárního souboru. Binární soubor popisuje všechny exportované typy, funkce a šablony v modulu. Když zdrojový soubor importuje modul, kompilátor načte v binárním souboru, který obsahuje obsah modulu. Čtení binárního souboru je mnohem rychlejší než zpracování souboru hlavičky. Binární soubor je také znovu použit kompilátorem při každém importu modulu, což šetří ještě více času. Vzhledem k tomu, že se modul sestavuje jednou a ne pokaždé, když se importuje, může se čas sestavení zkrátit, někdy výrazně.

Důležitější je, že moduly nemají problémy s křehkostí, které soubory hlaviček dělají. Import modulu nemění sémantiku modulu ani sémantiku jakéhokoli jiného importovaného modulu. Makra, direktivy preprocesoru a neexportované názvy deklarované v modulu nejsou viditelné pro zdrojový soubor, který ho importuje. Moduly můžete importovat v libovolném pořadí a nezměníte význam modulů.

Moduly lze používat vedle souborů hlaviček. Tato funkce je vhodná, pokud migrujete základ kódu tak, aby používal moduly, protože to můžete udělat ve fázích.

V některých případech lze soubor hlavičky importovat jako jednotku záhlaví, nikoli jako #include soubor. Jednotky hlaviček jsou doporučenou alternativou k předkompilovaným souborům hlaviček (PCH). Snadněji se nastavují a používají než sdílené soubory PCH , ale poskytují podobné výhody výkonu. Další informace naleznete v tématu Návod: Sestavení a import jednotek hlaviček v sadě Microsoft Visual C++.

Váš kód může automaticky využívat moduly ve stejném projektu nebo jakékoli odkazované projekty pomocí odkazů na projekty typu projekt-projekt na statické knihovny.

Vytvoření projektu

Při vytváření jednoduchého projektu se podíváme na různé aspekty modulů. Projekt implementuje rozhraní API pomocí modulu místo souboru hlavičky.

V sadě Visual Studio 2022 nebo novější zvolte Vytvořit nový projekt a potom typ projektu Konzolová aplikace (pro C++). Pokud tento typ projektu není k dispozici, možná jste při instalaci sady Visual Studio nevybrali vývoj desktopových aplikací pomocí úlohy C++ . Pomocí Instalační program pro Visual Studio můžete přidat úlohu C++.

Pojmenujte nový projekt ModulesTutorial a vytvořte projekt.

Vzhledem k tomu, že moduly jsou funkce C++20, použijte možnost nebo/std:c++latestmožnost kompilátoru/std:c++20. V Průzkumník řešení klikněte pravým tlačítkem myši na název ModulesTutorialprojektu a pak zvolte Vlastnosti. V dialogovém okně Stránky vlastností projektu změňte konfiguraci na Všechny konfigurace a platformy na všechny platformy. V podokně stromového zobrazení vlevo vyberte Obecné vlastnosti>konfigurace. Vyberte vlastnost Standard jazyka C++. Pomocí rozevíracího seznamu změňte hodnotu vlastnosti na STANDARD ISO C++20 (/std:c++20). Pokud chcete změnu přijmout, vyberte OK .

A screenshot of the ModulesTutorial property page with the left pane open to Configuration Properties > General, and the C++ Language Standard dropdown open with ISO C++20 Standard (/std:c++20) selected

Vytvoření jednotky rozhraní primárního modulu

Modul se skládá z jednoho nebo více souborů. Jeden z těchto souborů musí být to, co se nazývá primární jednotka rozhraní modulu. Definuje, co modul exportuje; to znamená, jaké dovozce modulu uvidí. Pro každý modul může existovat pouze jedna jednotka rozhraní primárního modulu.

Pokud chcete přidat primární jednotku rozhraní modulu, klikněte v Průzkumník řešení pravým tlačítkem na Zdrojové soubory a pak vyberte Přidat>modul.

Add item dialog in solution explorer with Add > Module... highlighted to illustrate where to click to add a module.

V dialogovém okně Přidat novou položku , které se zobrazí, zadejte název BasicPlane.Figures.ixx nového modulu a zvolte Přidat.

Výchozí obsah vytvořeného souboru modulu má dva řádky:

export module BasicPlane;

export void MyFunc();

Klíčová export module slova na prvním řádku deklarují, že tento soubor je jednotkou rozhraní modulu. Tady je malý bod: pro každý pojmenovaný modul musí být přesně jedna jednotka rozhraní modulu bez zadaného oddílu modulu. Tato jednotka modulu se nazývá primární jednotka rozhraní modulu.

Primární jednotka rozhraní modulu je místo, kde deklarujete funkce, typy, šablony, další moduly a oddíly modulů, které se zpřístupní při importu zdrojových souborů. Modul se může skládat z více souborů, ale pouze soubor rozhraní primárního modulu identifikuje, co se má zveřejnit.

BasicPlane.Figures.ixx Obsah souboru nahraďte následujícím kódem:

export module BasicPlane.Figures; // the export module keywords mark this file as a primary module interface unit

Tento řádek identifikuje tento soubor jako primární rozhraní modulu a dává modulu název: BasicPlane.Figures. Tečka v názvu modulu nemá pro kompilátor žádný zvláštní význam. Pomocí období můžete sdělit, jak je modul uspořádaný. Pokud máte více souborů modulů, které spolupracují, můžete použít tečky k označení oddělení obav. V tomto kurzu použijeme tečky k označení různých funkčních oblastí rozhraní API.

Tento název je také tam, odkud pochází "pojmenovaný" v "pojmenovaném modulu". Soubory, které jsou součástí tohoto modulu, používají tento název k tomu, aby se identifikovaly jako součást pojmenovaného modulu. Pojmenovaný modul je kolekce jednotek modulů se stejným názvem modulu.

Měli bychom si promluvit o rozhraní API, které budeme implementovat ještě chvíli, než budeme pokračovat. Má vliv na volby, které provedeme v dalším kroku. Rozhraní API představuje různé obrazce. V tomto příkladu poskytneme pouze několik obrazců: Point a Rectangle. Point je určen k použití jako součást složitějších obrazců, například Rectangle.

Abychom si ukázali některé funkce modulů, zabereme toto rozhraní API do částí. Jednou z nich bude Point rozhraní API. Druhá část bude Rectangle. Představte si, že toto rozhraní API se rozšíří do něčeho složitějšího. Rozdělení je užitečné pro oddělení problémů nebo usnadnění údržby kódu.

Zatím jsme vytvořili primární rozhraní modulu, které toto rozhraní API zveřejní. Point Teď vytvoříme rozhraní API. Chceme, aby byl součástí tohoto modulu. Z důvodů logické organizace a potenciální efektivity sestavení chceme tuto část rozhraní API snadno pochopit sami. K tomu vytvoříme soubor oddílu modulu.

Soubor oddílu modulu je kus nebo součást modulu. To, co je jedinečné, je, že může být považováno za jednotlivou část modulu, ale pouze v rámci modulu. Oddíly modulů nelze využívat mimo modul. Oddíly modulů jsou užitečné pro rozdělení implementace modulu na spravovatelné části.

Při importu oddílu do primárního modulu se všechny jeho deklarace zobrazí primárnímu modulu bez ohledu na to, jestli se exportují. Oddíly je možné importovat do libovolného rozhraní oddílů, primárního rozhraní modulu nebo jednotky modulu, které patří do pojmenovaného modulu.

Vytvoření souboru oddílu modulu

Point oddíl modulu

Pokud chcete vytvořit soubor oddílu modulu, klikněte v Průzkumník řešení pravým tlačítkem na Zdrojové soubory a pak vyberte Přidat>modul. Pojmenujte soubor BasicPlane.Figures-Point.ixx a zvolte Přidat.

Protože se jedná o soubor oddílu modulu, přidali jsme do názvu modulu pomlčka a název oddílu. Tato konvence pomáhá kompilátoru v případě příkazového řádku, protože kompilátor používá pravidla vyhledávání názvů na základě názvu modulu k vyhledání zkompilovaného .ifc souboru pro oddíl. Tímto způsobem nemusíte zadávat explicitní /reference argumenty příkazového řádku, abyste našli oddíly, které patří do modulu. Je také užitečné uspořádat soubory, které patří do modulu podle názvu, protože můžete snadno zjistit, které soubory patří do kterých modulů.

Nahraďte obsah BasicPlane.Figures-Point.ixx tímto obsahem:

export module BasicPlane.Figures:Point; // defines a module partition, Point, that's part of the module BasicPlane.Figures

export struct Point
{
    int x, y;
};

Soubor začíná export modulena . Tato klíčová slova jsou také tím, jak začíná rozhraní primárního modulu. Čím se tento soubor liší, je dvojtečka (:) za názvem modulu, za kterým následuje název oddílu. Tato konvence vytváření názvů identifikuje soubor jako oddíl modulu. Protože definuje rozhraní modulu pro oddíl, nepovažuje se za primární rozhraní modulu.

Název BasicPlane.Figures:Point identifikuje tento oddíl jako součást modulu BasicPlane.Figures. (Nezapomeňte, že tečka v názvu nemá žádný zvláštní význam pro kompilátor). Dvojtečka označuje, že tento soubor obsahuje oddíl modulu s názvem Point , který patří do modulu BasicPlane.Figures. Tento oddíl můžeme importovat do jiných souborů, které jsou součástí tohoto pojmenovaného modulu.

V tomto souboru export se struct Point klíčové slovo zpřístupní příjemcům.

Rectangle oddíl modulu

Dalším oddílem, který definujeme, je Rectangle. Vytvořte jiný soubor modulu stejným postupem jako předtím: V Průzkumník řešení klikněte pravým tlačítkem na Zdrojové soubory a pak vyberte Přidat>modul. Pojmenujte soubor BasicPlane.Figures-Rectangle.ixx a vyberte Přidat.

Nahraďte obsah BasicPlane.Figures-Rectangle.ixx tímto obsahem:

export module BasicPlane.Figures:Rectangle; // defines the module partition Rectangle

import :Point;

export struct Rectangle // make this struct visible to importers
{
    Point ul, lr;
};

// These functions are declared, but will
// be defined in a module implementation file
export int area(const Rectangle& r);
export int height(const Rectangle& r);
export int width(const Rectangle& r);

Soubor začíná export module BasicPlane.Figures:Rectangle; deklarací oddílu modulu, který je součástí modulu BasicPlane.Figures. Přidané :Rectangle do názvu modulu ho definuje jako oddíl modulu BasicPlane.Figures. Dá se importovat jednotlivě do libovolného souboru modulu, který je součástí tohoto pojmenovaného modulu.

Dále ukazuje, import :Point; jak importovat oddíl modulu. Tento import příkaz zviditelní všechny exportované typy, funkce a šablony v oddílu modulu. Nemusíte zadávat název modulu. Kompilátor ví, že tento soubor patří do BasicPlane.Figures modulu kvůli export module BasicPlane.Figures:Rectangle; horní části souboru.

Dále kód exportuje definici struct Rectangle a deklarace některých funkcí, které vracejí různé vlastnosti obdélníku. Klíčové export slovo označuje, jestli se má předcházet tomu, co předchází příjemcům modulu. Používá se k tomu, aby byly funkce area, heighta width viditelné mimo modul.

Všechny definice a deklarace v oddílu modulu jsou viditelné pro jednotku importujícího modulu bez ohledu na export to, jestli mají klíčové slovo nebo ne. Klíčové export slovo určuje, jestli bude definice, deklarace nebo typedef viditelná mimo modul při exportu oddílu v primárním rozhraní modulu.

Názvy se uživatelům modulu zviditelní několika způsoby:

  • Klíčové slovo export umístěte před každý typ, funkci a tak dále, které chcete exportovat.
  • Pokud jste například umístili export před obor názvů export namespace N { ... }, vše definované ve složených závorkách se exportuje. Pokud ale v modulu, který definujetenamespace N { struct S {...};}struct S, není k dispozici pro uživatele modulu. Není k dispozici, protože deklarace oboru názvů není předzvěděná export, i když existuje jiný obor názvů se stejným názvem, který je.
  • Pokud typ, funkce atd., neměl by být exportován, vynechat export klíčové slovo. Zobrazí se ostatním souborům, které jsou součástí modulu, ale ne pro dovozce modulu.
  • Slouží module :private; k označení začátku oddílu privátního modulu. Oddíl soukromého modulu je oddíl modulu, ve kterém jsou deklarace viditelné pouze pro daný soubor. Nejsou viditelné pro soubory, které tento modul importují, ani do jiných souborů, které jsou součástí tohoto modulu. Představte si ho jako oddíl, který je pro soubor statický. Tento oddíl je viditelný pouze v rámci souboru.
  • Pokud chcete, aby byl importovaný modul nebo oddíl modulu viditelný, použijte export import. Příklad je uvedený v další části.

Vytvoření oddílů modulu

Když teď máme dvě části rozhraní API definované, pojďme je spojit, abychom k nim mohli přistupovat jako k souborům, které tento modul importují.

Všechny oddíly modulu musí být zpřístupněny jako součást definice modulu, do které patří. Oddíly se zveřejňují v rozhraní primárního modulu. BasicPlane.Figures.ixx Otevřete soubor, který definuje primární rozhraní modulu. Nahraďte jeho obsah následujícím kódem:

export module BasicPlane.Figures; // keywords export module marks this as a primary module interface unit

export import :Point; // bring in the Point partition, and export it to consumers of this module
export import :Rectangle; // bring in the Rectangle partition, and export it to consumers of this module

Dva řádky, které začínají export import , jsou tady nové. Když se takto zkombinují, dávají kompilátoru pokyn, aby importoval zadaný modul a aby byl viditelný pro uživatele tohoto modulu. V tomto případě dvojtečka (:) v názvu modulu označuje, že importujeme oddíl modulu.

Importované názvy neobsahují úplný název modulu. Například :Point oddíl byl deklarován jako export module BasicPlane.Figures:Point. Ale tady importujeme :Point. Vzhledem k tomu, že jsme v souboru rozhraní primárního modulu pro modul BasicPlane.Figures, je název modulu implicitní a je zadán pouze název oddílu.

Zatím jsme definovali primární rozhraní modulu, které zpřístupňuje rozhraní API, které chceme zpřístupnit. Ale deklarovali jsme pouze, nedefinovali, area()height()nebo width(). Provedeme to dále vytvořením souboru implementace modulu.

Vytvoření souboru implementace jednotek modulu

Soubory implementace jednotek modulu nekončí příponou .ixx – jsou to normální .cpp soubory. Přidejte soubor implementace jednotek modulu tak, že vytvoříte zdrojový soubor kliknutím pravým tlačítkem v Průzkumník řešení ve zdrojových souborech, vyberte Přidat>novou položku a pak vyberte Soubor C++ (.cpp). Pojmenujte nový soubor BasicPlane.Figures-Rectangle.cppa pak zvolte Přidat.

Zásady vytváření názvů pro implementační soubor oddílu modulu se řídí konvencí pojmenování oddílu. Má ale příponu .cpp , protože se jedná o implementační soubor.

BasicPlane.Figures-Rectangle.cpp Obsah souboru nahraďte následujícím kódem:

module;

// global module fragment area. Put #include directives here 

module BasicPlane.Figures:Rectangle;

int area(const Rectangle& r) { return width(r) * height(r); }
int height(const Rectangle& r) { return r.ul.y - r.lr.y; }
int width(const Rectangle& r) { return r.lr.x - r.ul.x; }

Tento soubor začíná module; tím, že představuje zvláštní oblast modulu označovanou jako globální fragment modulu. Předchází kódu pro pojmenovaný modul a je tam, kde můžete použít direktivy preprocesoru, jako #includeje . Kód v globálním fragmentu modulu není vlastněný ani exportován rozhraním modulu.

Pokud zahrnete hlavičkový soubor, obvykle nechcete, aby se s ním zacházelo jako s exportovanou částí modulu. Soubor hlaviček obvykle zahrnete jako podrobnosti implementace, které by neměly být součástí rozhraní modulu. Může se jednat o pokročilé případy, kdy to chcete udělat, ale obecně ne. Pro direktivy globálního fragmentu modulu nejsou generována #include žádná samostatná metadata (.ifcsoubory). Globální fragmenty modulů poskytují vhodné místo pro zahrnutí souborů hlaviček, jako windows.hjsou , nebo v Linuxu, unistd.h.

Soubor implementace modulu, který vytváříme, neobsahuje žádné knihovny, protože je nepotřebuje jako součást jeho implementace. Ale pokud ano, tato oblast je místo, kde by #include direktivy jdou.

Řádek module BasicPlane.Figures:Rectangle; označuje, že tento soubor je součástí pojmenovaného modulu BasicPlane.Figures. Kompilátor do tohoto souboru automaticky přenese typy a funkce vystavené rozhraním primárního modulu. Jednotka implementace modulu nemá export klíčové slovo před klíčovým slovem module v deklaraci modulu.

Dále jsou definice funkcí area(), height()a width(). Byly deklarovány v oddílu Rectangle v BasicPlane.Figures-Rectangle.ixx. Vzhledem k tomu, že primární rozhraní modulu pro tento modul importoval Point oddíly a Rectangle oddíly modulu, jsou tyto typy viditelné zde v souboru implementace jednotek modulu. Zajímavá funkce jednotek implementace modulu: Kompilátor automaticky zviditelní vše v odpovídajícím primárním rozhraní modulu pro soubor. Není potřeba.imports <module-name>

Cokoli, co deklarujete v rámci implementační jednotky, je viditelné pouze pro modul, ke kterému patří.

Import modulu

Teď použijeme modul, který jsme definovali. Otevřete soubor ModulesTutorial.cpp. Byl vytvořen automaticky jako součást projektu. V současné době obsahuje funkci main(). Nahraďte jeho obsah následujícím kódem:

#include <iostream>

import BasicPlane.Figures;

int main()
{
    Rectangle r{ {1,8}, {11,3} };

    std::cout << "area: " << area(r) << '\n';
    std::cout << "width: " << width(r) << '\n';

    return 0;
}

Tento příkaz import BasicPlane.Figures; zviditelňuje všechny exportované funkce a typy z BasicPlane.Figures modulu pro tento soubor. Může přijít před nebo po jakýchkoli #include direktivách.

Aplikace pak pomocí typů a funkcí z modulu vypíše oblast a šířku definovaného obdélníku:

area: 50
width: 10

Anatomie modulu

Teď se podrobněji podíváme na různé soubory modulů.

Rozhraní primárního modulu

Modul se skládá z jednoho nebo více souborů. Jeden z nich definuje rozhraní, které uvidí dovozci. Tento soubor obsahuje rozhraní primárního modulu. Pro každý modul může existovat pouze jedno primární rozhraní modulu. Jak už bylo uvedeno dříve, jednotka rozhraní exportovaného modulu nezadá oddíl modulu.

Ve výchozím nastavení má .ixx rozšíření. Zdrojový soubor ale můžete považovat za soubor rozhraní modulu s libovolnou příponou. Uděláte to tak, že na kartě Upřesnit nastavíte vlastnost Compile As (Kompilace jako) na stránce vlastností zdrojového souboru na hodnotu Compile As Module (/interface):

Screenshot of a hypothetical source file's Configuration properties under Configuration properties > C/C++ > Advanced > Compile As, with Compile as C++ Module Code (/interface) highlighted

Základní osnova definičního souboru rozhraní modulu je:

module; // optional. Defines the beginning of the global module fragment

// #include directives go here but only apply to this file and
// aren't shared with other module implementation files.
// Macro definitions aren't visible outside this file, or to importers.
// import statements aren't allowed here. They go in the module preamble, below.

export module [module-name]; // Required. Marks the beginning of the module preamble

// import statements go here. They're available to all files that belong to the named module
// Put #includes in the global module fragment, above

// After any import statements, the module purview begins here
// Put exported functions, types, and templates here

module :private; // optional. The start of the private module partition.

// Everything after this point is visible only within this file, and isn't 
// visible to any of the other files that belong to the named module.

Tento soubor musí začínat buď module; tím, že označuje začátek globálního fragmentu modulu, nebo export module [module-name]; musí indikovat začátek modulu purview.

Purview modulu je místo, kde funkce, typy, šablony atd., jdou z modulu zpřístupnit.

Můžete také vystavit další moduly nebo oddíly modulů prostřednictvím export import klíčových slov, jak je znázorněno BasicPlane.Figures.ixx v souboru.

Primární soubor rozhraní musí exportovat všechny oddíly rozhraní definované pro modul přímo nebo nepřímo nebo program je špatně vytvořený.

Oddíl soukromého modulu je místo, kde můžete dát věci, které chcete zobrazit pouze v tomto souboru.

Modulové jednotky rozhraní předchází klíčovému slovu module klíčovým slovem export.

Podrobnější informace o syntaxi modulu najdete v tématu Moduly.

Jednotky implementace modulu

Jednotky implementace modulu patří do pojmenovaného modulu. Pojmenovaný modul, do který patří, je označen příkazem module [module-name] v souboru. Jednotky implementace modulu poskytují podrobnosti implementace, které z hygieny kódu nebo z jiných důvodů nechcete vložit do primárního rozhraní modulu nebo do souboru oddílu modulu.

Jednotky implementace modulu jsou užitečné pro rozdělení velkého modulu na menší části, což může vést k rychlejším sestavením. Tato technika je stručně popsaná v části Osvědčené postupy .

Soubory jednotek implementace modulu mají příponu .cpp . Základní osnova souboru jednotky implementace modulu je:

// optional #include or import statements. These only apply to this file
// imports in the associated module's interface are automatically available to this file

module [module-name]; // required. Identifies which named module this implementation unit belongs to

// implementation

Soubory oddílů modulu

Oddíly modulů poskytují způsob, jak modul integrovat do různých částí nebo oddílů. Oddíly modulů se mají importovat jenom v souborech, které jsou součástí pojmenovaného modulu. Nedají se importovat mimo pojmenovaný modul.

Oddíl má soubor rozhraní a nula nebo více implementačních souborů. Oddíl modulu sdílí vlastnictví všech deklarací v celém modulu.

Všechny názvy exportované soubory rozhraní oddílů musí být importovány a znovu exportovány (export import) souborem primárního rozhraní. Název oddílu musí začínat názvem modulu, za kterým následuje dvojtečka a pak název oddílu.

Základní přehled souboru rozhraní oddílu vypadá takto:

module; // optional. Defines the beginning of the global module fragment

// This is where #include directives go. They only apply to this file and aren't shared
// with other module implementation files.
// Macro definitions aren't visible outside of this file or to importers
// import statements aren't allowed here. They go in the module preamble, below

export module [Module-name]:[Partition name]; // Required. Marks the beginning of the module preamble

// import statements go here. 
// To access declarations in another partition, import the partition. Only use the partition name, not the module name.
// For example, import :Point;
// #include directives don't go here. The recommended place is in the global module fragment, above

// export imports statements go here

// after import, export import statements, the module purview begins
// put exported functions, types, and templates for the partition here

module :private; // optional. Everything after this point is visible only within this file, and isn't 
                         // visible to any of the other files that belong to the named module.
...

Osvědčené postupy pro moduly

Modul a kód, který importuje, musí být zkompilovány se stejnými možnostmi kompilátoru.

Pojmenování modulů

  • V názvech modulů můžete použít tečky (.), ale nemají pro kompilátor žádný zvláštní význam. Použijte je k vyjádření významu uživatelům vašeho modulu. Začněte například s knihovnou nebo hlavním oborem názvů projektu. Dokončete název, který popisuje funkce modulu. BasicPlane.Figures má vyjádřit rozhraní API pro geometrické roviny a konkrétně obrázky, které lze reprezentovat v rovině.
  • Název souboru, který obsahuje primární rozhraní modulu, je obecně název modulu. Například vzhledem k názvu BasicPlane.Figuresmodulu by název souboru obsahujícího primární rozhraní byl pojmenován BasicPlane.Figures.ixx.
  • Název souboru oddílu modulu je obvykle <primary-module-name>-<module-partition-name> tam, kde za ním následuje pomlčka (-) a název oddílu. Například BasicPlane.Figures-Rectangle.ixx

Pokud vytváříte z příkazového řádku a používáte tuto konvenci vytváření názvů pro oddíly modulu, nemusíte explicitně přidávat /reference pro každý soubor oddílů modulu. Kompilátor je vyhledá automaticky na základě názvu modulu. Název zkompilovaného souboru oddílu (končící příponou .ifc ) se vygeneruje z názvu modulu. Vezměte v úvahu název BasicPlane.Figures:Rectanglemodulu: kompilátor očekává, že odpovídající zkompilovaný soubor oddílu pro Rectangle název BasicPlane.Figures-Rectangle.ifc. Kompilátor používá toto schéma pojmenování, aby bylo snazší používat oddíly modulů tím, že automaticky vyhledá soubory jednotek rozhraní pro oddíly.

Můžete je pojmenovat pomocí vlastní konvence. Pak ale budete muset zadat odpovídající /reference argumenty kompilátoru příkazového řádku.

Moduly faktoru

Za účelem snadnější údržby kódu a potenciálně rychlejší kompilace použijte implementační soubory a oddíly modulu.

Například přesunutí implementace modulu z definičního souboru rozhraní modulu a do souboru implementace modulu znamená, že změny implementace nemusí nutně způsobit, že každý soubor, který importuje modul znovu kompilovat (pokud nemáte inline implementace).

Oddíly modulů usnadňují logické faktorování velkého modulu. Dají se použít ke zlepšení doby kompilace, aby změny části implementace nezpůsobily rekompilování všech souborů modulu.

Shrnutí

V tomto kurzu jste se seznámili se základy modulů C++20. Vytvořili jste primární rozhraní modulu, definovali jste oddíl modulu a vytvořili jste soubor implementace modulu.

Viz také

Přehled modulů v jazyce C++
module, import, export klíčová slova
Prohlídka modulů C++ v sadě Visual Studio
Praktické moduly C++20 a budoucnost nástrojů kolem modulů C++
Přesunutí projektu do modulů s názvem C++
Návod: Sestavení a import jednotek hlaviček v Microsoft Visual C++