Sdílet prostřednictvím


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.threadingposkytuje 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 Examplejiné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-seqRozhodnoutidentifier

module-name-qualifier-seq:
identifier .
module-name-qualifier-seq identifier .

module-partition:
: module-name

module-declaration:
exportoptmodule-nameoptattribute-specifier-seqmodulemodule-partition;

module-import-declaration:
exportopt optimportmodule-nameattribute-specifier-seq;
exportopt optimportmodule-partitionattribute-specifier-seq;
exportopt optimportheader-nameattribute-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, , importexport
Kurz pojmenovaných modulů
Porovnání jednotek záhlaví, modulů a předkompilovaných hlaviček