Přehled modulů v C++
C++20 zavádí moduly. Modul je sada souborů zdrojového kódu, které jsou kompilovány nezávisle na zdrojových souborech (přesněji řečeno, jednotky překladu, které je importují.
Moduly eliminují nebo snižují řadu problémů spojených s používáním souborů hlaviček. Často zkracují časy kompilace, někdy výrazně. Makra, direktivy preprocesoru a nevyexportované názvy deklarované v modulu nejsou viditelné mimo modul. Nemají žádný vliv na kompilaci jednotky překladu, která modul importuje. Moduly můžete importovat v libovolném pořadí bez obav o předdefinování maker. Deklarace v jednotce importu překladu se v importovaném modulu nezúčastní překladu přetížení ani vyhledávání názvů. Po zkompilování modulu se výsledky uloží do binárního souboru, který popisuje všechny exportované typy, funkce a šablony. Kompilátor může tento soubor zpracovat mnohem rychleji než soubor hlaviček. Kompilátor ho může znovu použít na každém místě, kde je modul importován do projektu.
Moduly můžete používat vedle souborů hlaviček. Zdrojový soubor C++ může import
modulovat a také #include
hlavičkové soubory. V některých případech můžete importovat soubor hlaviček jako modul, což je rychlejší než jeho zpracování #include
pomocí preprocesoru. Doporučujeme používat moduly v nových projektech místo co nejvíce hlavičkových souborů. U větších stávajících projektů v aktivním vývoji experimentujte s převodem starších hlaviček na moduly. Založte svůj přechod na to, jestli získáte smysluplné zkrácení časů kompilace.
Pokud chcete porovnat moduly s jinými způsoby importu standardní knihovny, přečtěte si téma Porovnání jednotek záhlaví, modulů a předkompilovaných hlaviček.
Povolení modulů v kompilátoru Microsoft C++
Od sady Visual Studio 2022 verze 17.1 jsou standardní moduly C++20 plně implementovány v kompilátoru Microsoft C++.
Před určením standardu C++20 měl Microsoft experimentální podporu modulů. Kompilátor také podporoval import předem připravených modulů standardní knihovny, které jsou popsané níže.
Počínaje sadou Visual Studio 2022 verze 17.5 je import standardní knihovny jako modulu standardizovaný i plně implementovaný v kompilátoru Microsoft C++. Tato část popisuje starší experimentální metodu, která je stále podporovaná. Informace o novém standardizovaném způsobu importu standardní knihovny pomocí modulů naleznete v tématu Import standardní knihovny C++ pomocí modulů.
Pomocí funkce modulů můžete vytvořit moduly s jedním oddílem a importovat moduly standardní knihovny poskytované Microsoftem. Pokud chcete povolit podporu modulů standardní knihovny, zkompilujte je pomocí /experimental:module
a /std:c++latest
. V projektu sady Visual Studio klikněte pravým tlačítkem myši na uzel projektu v Průzkumník řešení a zvolte Vlastnosti. Nastavte rozevírací seznam Konfigurace na Všechny konfigurace a pak zvolte Vlastnosti>konfigurace C/C++Language>Enable C++> Modules (experimentální).
Modul a kód, který ho využívá, musí být zkompilovány se stejnými možnostmi kompilátoru.
Využívání standardní knihovny C++ jako modulů (experimentální)
Tato část popisuje experimentální implementaci, která je stále podporována. Nový standardizovaný způsob využívání standardní knihovny C++ jako moduly je popsán v importu standardní knihovny C++ pomocí modulů.
Importem standardní knihovny C++ jako modulů místo zahrnutím do souborů hlaviček můžete potenciálně zrychlit časy kompilace v závislosti na velikosti projektu. Experimentální knihovna je rozdělená na následující pojmenované moduly:
std.regex
poskytuje obsah záhlaví.<regex>
std.filesystem
poskytuje obsah záhlaví.<filesystem>
std.memory
poskytuje obsah záhlaví.<memory>
std.threading
poskytuje obsah hlaviček<atomic>
, ,<condition_variable>
<future>
,<mutex>
, ,<shared_mutex>
a<thread>
std.core
poskytuje vše ostatní v standardní knihovně jazyka C++
Pokud chcete tyto moduly využívat, přidejte do horní části souboru zdrojového kódu deklaraci importu. Příklad:
import std.core;
import std.regex;
Pokud chcete využívat moduly Microsoft Standard Library, zkompilujte program s možnostmi /EHsc
a /MD
možnostmi.
Příklad
Následující příklad ukazuje jednoduchou definici modulu ve zdrojovém souboru s názvem Example.ixx
. Rozšíření .ixx
se vyžaduje pro soubory rozhraní modulů v sadě Visual Studio. V tomto příkladu soubor rozhraní obsahuje definici funkce i deklaraci. Definice ale můžete také umístit do jednoho nebo více samostatných souborů implementace modulu, jak je znázorněno v pozdějším příkladu.
Příkaz export module Example;
označuje, že tento soubor je primárním rozhraním modulu volaný Example
. export
Modifikátor na f()
značí, že tato funkce je viditelná při importu Example
jiného programu nebo modulu .
// Example.ixx
export module Example;
#define ANSWER 42
namespace Example_NS
{
int f_internal() {
return ANSWER;
}
export int f() {
return f_internal();
}
}
Soubor MyProgram.cpp
používá import
pro přístup k názvu exportu .Example
Název Example_NS
oboru názvů je zde viditelný, ale ne všechny jeho členy, protože se neexportují. Makro také není viditelné, ANSWER
protože makra nejsou exportována.
// MyProgram.cpp
import Example;
import std.core;
using namespace std;
int main()
{
cout << "The result of f() is " << Example_NS::f() << endl; // 42
// int i = Example_NS::f_internal(); // C2039
// int j = ANSWER; //C2065
}
Deklarace import
se může zobrazit pouze v globálním oboru.
Gramatika modulu
module-name
:
module-name-qualifier-seq
volitidentifier
module-name-qualifier-seq
:
identifier
.
module-name-qualifier-seq
identifier
.
module-partition
:
:
module-name
module-declaration
:
export
optmodule-partition
optattribute-specifier-seq
module
module-name
;
module-import-declaration
:
export
opt optimport
module-name
attribute-specifier-seq
;
export
opt optimport
module-partition
attribute-specifier-seq
;
export
opt optimport
header-name
attribute-specifier-seq
;
Implementace modulů
Rozhraní modulu exportuje název modulu a všechny obory názvů, typy, funkce atd., které tvoří veřejné rozhraní modulu.
Implementace modulu definuje věci exportované modulem.
V nejjednodušší podobě může být modul jedním souborem, který kombinuje rozhraní modulu a implementaci. Implementaci můžete také umístit do jednoho nebo více samostatných implementačních souborů modulu, podobně jako v případě .h
a .cpp
souborů.
U větších modulů můžete části modulu rozdělit do dílčích modulů označovaných jako oddíly. Každý oddíl se skládá ze souboru rozhraní modulu, který exportuje název oddílu modulu. Oddíl může mít také jeden nebo více souborů implementace oddílu. Modul jako celek má jedno primární rozhraní modulu, což je veřejné rozhraní modulu. V případě potřeby může rozhraní oddílů exportovat.
Modul se skládá z jedné nebo více jednotek modulu. Jednotka modulu je jednotka překladu (zdrojový soubor), která obsahuje deklaraci modulu. Existuje několik typů jednotek modulu:
- Jednotka rozhraní modulu exportuje název modulu nebo název oddílu modulu. Jednotka rozhraní modulu má
export module
v deklaraci modulu. - Jednotka implementace modulu neexportuje název modulu ani název oddílu modulu. Jak název napovídá, implementuje modul.
- Primární jednotka rozhraní modulu exportuje název modulu. V modulu musí existovat pouze jedna jednotka rozhraní primárního modulu.
- Jednotka rozhraní oddílu modulu exportuje název oddílu modulu.
- Jednotka implementace oddílu modulu má v deklaraci modulu název oddílu modulu, ale žádné
export
klíčové slovo.
Klíčové export
slovo se používá pouze v souborech rozhraní. Implementační soubor může import
jiný modul, ale nemůže export
obsahovat žádné názvy. Soubory implementace můžou mít příponu.
Moduly, obory názvů a vyhledávání závislé na argumentech
Pravidla pro obory názvů v modulech jsou stejná jako jakýkoli jiný kód. Pokud se exportuje deklarace v rámci oboru názvů, je také implicitně exportován nadřazený obor názvů (s výjimkou členů, které nejsou explicitně exportovány v daném oboru názvů). Pokud je obor názvů explicitně exportován, exportují se všechny deklarace v rámci této definice oboru názvů.
Když kompilátor hledá překlady přetížení v jednotce importu závislé na argumentech, považuje funkce deklarované ve stejné jednotce překladu (včetně rozhraní modulů), jako je typ argumentů funkce.
Oddíly modulů
Oddíl modulu se podobá modulu s výjimkou:
- Sdílí vlastnictví všech deklarací v celém modulu.
- Všechny názvy exportované soubory rozhraní oddílu se importují a exportují pomocí souboru primárního rozhraní.
- Název oddílu musí začínat názvem modulu a za ním dvojtečka (
:
). - Deklarace v libovolném oddílu jsou viditelné v celém modulu.\
- Nejsou nutná žádná zvláštní opatření, aby se zabránilo chybám pravidla odr (one-definition-rule). V jednom oddílu můžete deklarovat název (funkce, třída atd.) a definovat ho v jiném oddílu.
Soubor implementace oddílu začíná takto a je interním oddílem z hlediska standardů C++:
module Example:part1;
Soubor rozhraní oddílu začíná takto:
export module Example:part1;
Pokud chcete získat přístup k deklaracím v jiném oddílu, musí ho oddíl importovat. Může ale používat pouze název oddílu, nikoli název modulu:
module Example:part2;
import :part1;
Primární jednotka rozhraní musí importovat a znovu exportovat všechny soubory oddílů rozhraní modulu, například takto:
export import :part1;
export import :part2;
Primární jednotka rozhraní může importovat soubory implementace oddílů, ale nemůže je exportovat. Tyto soubory nesmí exportovat žádné názvy. Toto omezení umožňuje modulu zachovat interní podrobnosti implementace modulu.
Moduly a soubory hlaviček
Soubory hlaviček můžete zahrnout do zdrojového souboru modulu tak, že před deklaraci modulu vložíte #include
direktivu. Tyto soubory jsou považovány za fragment globálního modulu. Modul může zobrazit pouze názvy v globálním fragmentu modulu, které jsou v hlavičkách, které explicitně obsahuje. Fragment globálního modulu obsahuje pouze symboly, které se používají.
// MyModuleA.cpp
#include "customlib.h"
#include "anotherlib.h"
import std.core;
import MyModuleB;
//... rest of file
K řízení importovaných modulů můžete použít tradiční hlavičkový soubor:
// MyProgram.h
import std.core;
#ifdef DEBUG_LOGGING
import std.filesystem;
#endif
Importované soubory hlaviček
Některá záhlaví jsou dostatečně samostatná, aby je bylo možné převést pomocí klíčového import
slova. Hlavní rozdíl mezi importovanou hlavičkou a importovaným modulem spočívá v tom, že všechny definice preprocesoru v záhlaví jsou viditelné v importovacím programu hned za příkazem import
.
import <vector>;
import "myheader.h";
Viz také
module
, , import
export
Kurz pojmenovaných modulů
Porovnání jednotek záhlaví, modulů a předkompilovaných hlaviček
Váš názor
https://aka.ms/ContentUserFeedback.
Připravujeme: V průběhu roku 2024 budeme postupně vyřazovat problémy z GitHub coby mechanismus zpětné vazby pro obsah a nahrazovat ho novým systémem zpětné vazby. Další informace naleznete v tématu:Odeslat a zobrazit názory pro