Поделиться через


Руководство по именованным модулям (C++)

В этом руководстве описывается создание модулей C++20. Модули заменяют файлы заголовков. Вы узнаете, как модули являются улучшением файлов заголовков.

Из этого руководства вы узнаете, как:

  • Создание и импорт модуля
  • Создание основного блока интерфейса модуля
  • Создание файла секционирования модуля
  • Создание файла реализации единицы модуля

Необходимые компоненты

Для этого руководства требуется Visual Studio 2022 17.1.0 или более поздней версии.

При работе с примером кода в этом руководстве могут возникать ошибки IntelliSense. Работа с подсистемой IntelliSense догоняет компилятора. Ошибки IntelliSense можно игнорировать и не препятствовать созданию примера кода. Чтобы отслеживать ход выполнения работы IntelliSense, ознакомьтесь с этой проблемой.

Что такое модули C++

Файлы заголовков — это способ совместного использования объявлений и определений между исходными файлами в C++. Файлы заголовков являются хрупкими и трудными для создания. Они могут скомпилироваться по-разному в зависимости от порядка, в который они включены, или макросов, которые не определены. Они могут замедлить компиляцию, так как они повторно обработаны для каждого исходного файла, включающего их.

C++20 представляет современный подход к компонентизации программ C++: модулей.

Как и файлы заголовков, модули позволяют совместно использовать объявления и определения в исходных файлах. Но в отличие от файлов заголовков модули не утечки определений макросов или частных сведений о реализации.

Модули проще создавать, так как их семантика не изменяется из-за определений макросов или импорта, порядка импорта и т. д. Они также упрощают управление тем, что видно потребителям.

Модули обеспечивают дополнительную безопасность, чтобы файлы заголовков не были. Компилятор и компоновщик работают вместе, чтобы предотвратить возможные проблемы с конфликтом имен и обеспечить более строгие гарантии одного правила определения (ODR).

Модель строгой собственности избегает столкновений между именами во время связи, так как компоновщик присоединяет экспортированные имена к модулю, экспортируемом им. Эта модель позволяет компилятору Microsoft Visual C++ предотвратить неопределенное поведение, вызванное связыванием различных модулей, сообщающих аналогичные имена в одной программе. Дополнительные сведения см. в разделе "Строгое владение".

Модуль состоит из одного или нескольких файлов исходного кода, скомпилированных в двоичный файл. Двоичный файл описывает все экспортированные типы, функции и шаблоны в модуле. Когда исходный файл импортирует модуль, компилятор считывает двоичный файл, содержащий содержимое модуля. Чтение двоичного файла гораздо быстрее, чем обработка файла заголовка. Кроме того, двоичный файл повторно используется компилятором при каждом импорте модуля, сохраняя еще больше времени. Так как модуль создается один раз, а не каждый раз при импорте, время сборки может быть сокращено, иногда резко.

Более важно, что модули не имеют проблем с хрупкостью, которые выполняют файлы заголовков. Импорт модуля не изменяет семантику модуля или семантику любого импортированного модуля. Макросы, директивы препроцессора и не экспортированные имена, объявленные в модуле, не видны исходному файлу, который импортирует его. Модули можно импортировать в любом порядке, и они не изменят смысл модулей.

Модули можно использовать параллельно с файлами заголовков. Эта функция удобна, если вы переносите базу кода для использования модулей, так как это можно сделать на этапах.

В некоторых случаях файл заголовка можно импортировать как блок заголовка, а не как #include файл. В качестве альтернативы файлам предкомпилированных заголовков (PCH) рекомендуется использовать блоки заголовков. Они проще настроить и использовать, чем общие PCH-файлы , но они обеспечивают аналогичные преимущества производительности. Дополнительные сведения см. в пошаговом руководстве. Создание и импорт единиц заголовков в Microsoft Visual C++.

Код может использовать модули в том же проекте или любые проекты, на которые ссылается ссылка, автоматически с помощью ссылок на проекты статической библиотеки.

Создание проекта

По мере создания простого проекта мы рассмотрим различные аспекты модулей. Проект реализует API с помощью модуля вместо файла заголовка.

В Visual Studio 2022 или более поздней версии выберите "Создать проект", а затем тип проекта консольного приложения (для C++). Если этот тип проекта недоступен, возможно, при установке Visual Studio не выбрана рабочая нагрузка для настольных компьютеров с рабочей нагрузкой C++ . Установщик Visual Studio можно использовать для добавления рабочей нагрузки C++ .

Присвойте новому проекту имя ModulesTutorial и создайте проект.

Так как модули являются компонентом C++20, используйте /std:c++20 параметр или /std:c++latest компилятор. В Обозреватель решений щелкните правой кнопкой мыши имя ModulesTutorialпроекта, а затем выберите "Свойства". В диалоговом окне "Страницы свойств проекта" измените конфигурацию на все конфигурации и платформу на все платформы. Выберите "Свойства>конфигурации" в области представления дерева слева. Выберите свойство C++ Language Standard. Используйте раскрывающийся список, чтобы изменить значение свойства на ISO C++20 Standard (/std:c++20). Нажмите кнопку "ОК ", чтобы принять изменение.

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

Создание основного блока интерфейса модуля

Модуль состоит из одного или нескольких файлов. Один из этих файлов должен быть тем, что называется основной единицей интерфейса модуля. Он определяет, что экспортирует модуль; То есть, какие импортеры модуля будут видеть. Для каждого модуля может быть только одна единица основного интерфейса модуля.

Чтобы добавить основной модуль интерфейса модуля, в Обозреватель решений щелкните правой кнопкой мыши исходные файлы и выберите пункт "Добавить>модуль".

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

В появившемся диалоговом окне "Добавить новый элемент" присвойте новому модулю имя BasicPlane.Figures.ixx и нажмите кнопку "Добавить".

Содержимое созданного файла модуля по умолчанию содержит две строки:

export module BasicPlane;

export void MyFunc();

Ключевое слово export module в первой строке объявляют, что этот файл является единицей интерфейса модуля. Здесь есть тонкий момент: для каждого именованного модуля должно быть ровно одна единица интерфейса модуля без указанной секции модуля. Этот модуль модуля называется основной единицей интерфейса модуля.

Основная единица интерфейса модуля — объявлять функции, типы, шаблоны, другие модули и секции модулей для предоставления при импорте исходных файлов модуля. Модуль может состоять из нескольких файлов, но только основной файл интерфейса модуля определяет, что нужно предоставить.

Замените содержимое BasicPlane.Figures.ixx файла следующим:

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

Эта строка идентифицирует этот файл как основной интерфейс модуля и задает имя модуля: BasicPlane.Figures Период в имени модуля не имеет специального значения для компилятора. Период можно использовать для передачи порядка модуля. Если у вас несколько файлов модулей, которые работают вместе, можно использовать периоды, чтобы указать разделение проблем. В этом руководстве мы будем использовать периоды для указания различных функциональных областей API.

Это имя также относится к именованным в "именованном модуле". Файлы, которые являются частью этого модуля, используют это имя для идентификации себя как часть именованного модуля. Именованный модуль — это коллекция единиц модуля с тем же именем модуля.

Мы должны поговорить о API, который мы реализуем в течение некоторого момента, прежде чем продолжить. Это влияет на выбор, который мы делаем дальше. API представляет различные фигуры. В этом примере мы предоставим только несколько фигур: Point и Rectangle. Point предназначено для использования в составе более сложных фигур, таких как Rectangle.

Чтобы проиллюстрировать некоторые функции модулей, мы рассмотрим этот API в части. Одна часть будет Point API. Другая часть будет Rectangle. Представьте, что этот API будет расти в что-то более сложное. Разделение полезно для разделения проблем или упрощения обслуживания кода.

До сих пор мы создали основной интерфейс модуля, который будет предоставлять этот API. Давайте создадим Point API. Мы хотим, чтобы он был частью этого модуля. По соображениям логической организации и потенциальной эффективности построения мы хотим сделать эту часть API легко понятной самостоятельно. Для этого мы создадим файл секционирования модуля.

Файл секционирования модуля — это часть или компонент модуля. Что делает его уникальным, это то, что его можно рассматривать как отдельный элемент модуля, но только в модуле. Секции модулей нельзя использовать за пределами модуля. Секции модулей полезны для разделения реализации модуля на управляемые части.

При импорте секции в основной модуль все объявления становятся видимыми для основного модуля независимо от того, экспортируются ли они. Секции можно импортировать в любой интерфейс секции, основной интерфейс модуля или модуль модуля, принадлежащий именованным модулю.

Создание файла секционирования модуля

Point Раздел модуля

Чтобы создать файл секционирования модуля, в Обозреватель решений щелкните правой кнопкой мыши исходные файлы, а затем нажмите кнопку "Добавить>модуль". Назовите файл BasicPlane.Figures-Point.ixx и нажмите кнопку "Добавить".

Так как это файл секционирования модуля, мы добавили дефис и имя раздела в имя модуля. Это соглашение помогает компилятору в случае командной строки, так как компилятор использует правила подстановки имен на основе имени модуля для поиска скомпилированного .ifc файла для секции. Таким образом, вам не нужно предоставлять явные /reference аргументы командной строки, чтобы найти разделы, принадлежащие модулю. Это также полезно для организации файлов, принадлежащих модулю по имени, так как вы можете легко увидеть, к каким файлам относятся модули.

Замените содержимое BasicPlane.Figures-Point.ixx на:

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

export struct Point
{
    int x, y;
};

Файл начинается с export module. Эти ключевое слово также показано, как начинается основной интерфейс модуля. Что отличает этот файл от двоеточия (:) после имени модуля, за которым следует имя секции. Это соглашение об именовании определяет файл как раздел модуля. Так как он определяет интерфейс модуля для секции, он не считается основным интерфейсом модуля.

Имя BasicPlane.Figures:Point определяет эту секцию как часть модуля BasicPlane.Figures. (Помните, что период в имени не имеет особого значения компилятору). Двоеточие указывает, что этот файл содержит раздел модуля с именем Point , который принадлежит модулю BasicPlane.Figures. Эту секцию можно импортировать в другие файлы, которые входят в этот именованный модуль.

В этом файле export ключевое слово становится struct Point видимым для потребителей.

Rectangle Раздел модуля

Следующая секция, которую мы определим, — Rectangleэто . Создайте другой файл модуля, выполнив те же действия, что и раньше: в Обозреватель решений щелкните правой кнопкой мыши исходные файлы, а затем нажмите кнопку "Добавить>модуль". Присвойте файлу имя BasicPlane.Figures-Rectangle.ixx и нажмите Добавить.

Замените содержимое BasicPlane.Figures-Rectangle.ixx на:

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);

Файл начинается с export module BasicPlane.Figures:Rectangle; объявления секции модуля, которая входит в состав модуля BasicPlane.Figures. Добавленный :Rectangle в имя модуля определяет его как секцию модуля BasicPlane.Figures. Его можно импортировать отдельно в любой из файлов модулей, входящих в этот именованный модуль.

Далее показано, import :Point; как импортировать секцию модуля. Инструкция import делает все экспортированные типы, функции и шаблоны в секции модуля видимыми для модуля. Вам не нужно указывать имя модуля. Компилятор знает, что этот файл принадлежит модулю из-за export module BasicPlane.Figures:Rectangle; того, что он находится BasicPlane.Figures в верхней части файла.

Затем код экспортирует определение struct Rectangle и объявления для некоторых функций, возвращающих различные свойства прямоугольника. Ключевое слово export указывает, следует ли делать то, что он предшествует потребителям модуля. Он используется для создания функций areaheightи width видимых за пределами модуля.

Все определения и объявления в секции модуля видны импортируемой единице модуля независимо от того, есть export ли они ключевое слово или нет. Ключевое слово export определяет, будет ли определение, объявление или типдеф отображаться за пределами модуля при экспорте секции в основном интерфейсе модуля.

Имена становятся видимыми для потребителей модуля несколькими способами:

  • Поместите ключевое слово export перед каждым типом, функцией и т. д., которую вы хотите экспортировать.
  • Если вы помещаете export перед пространством имен, например export namespace N { ... }, экспортируется все, определенное в фигурных скобках. Но если в другом месте определяемого namespace N { struct S {...};}модуля, struct S то он недоступен потребителям модуля. Это недоступно, так как это объявление пространства имен не предопределено export, несмотря на то, что существует другое пространство имен с тем же именем, что и есть.
  • Если тип, функция и т. д. не следует экспортировать, опустите export ключевое слово. Он будет виден другим файлам, которые являются частью модуля, но не для импорта модуля.
  • Используется module :private; для пометки начала раздела частного модуля. Раздел частного модуля — это раздел модуля, в котором объявления отображаются только для этого файла. Они не видны файлам, импортируемым этим модулем или другим файлам, которые являются частью этого модуля. Подумайте о нем как о разделе, который является статическим локальным для файла. Этот раздел отображается только в файле.
  • Чтобы сделать импортированный модуль или раздел модуля видимым, используйте export import. Пример показан в следующем разделе.

Создание секций модуля

Теперь, когда у нас есть две части API, давайте сведем их вместе, чтобы файлы, импортируемые этим модулем, могли получить доступ к ним в целом.

Все секции модулей должны предоставляться в рамках определения модуля, к которому они относятся. Секции предоставляются в основном интерфейсе модуля. BasicPlane.Figures.ixx Откройте файл, который определяет основной интерфейс модуля. Замените его содержимое следующим:

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

Две линии, начинающиеся с export import , являются новыми здесь. В сочетании с этим эти два ключевое слово указывают компилятору импортировать указанный модуль и сделать его видимым для потребителей этого модуля. В этом случае двоеточие (:) в имени модуля указывает, что импортируем секцию модуля.

Импортированные имена не включают полное имя модуля. Например, :Point раздел был объявлен как export module BasicPlane.Figures:Point. Тем не менее, мы импортируем :Point. Так как мы в основном файле интерфейса модуля для модуля, имя модуля BasicPlane.Figuresподразумевается, и указывается только имя секции.

До сих пор мы определили основной интерфейс модуля, который предоставляет поверхность API, которую мы хотим сделать доступной. Но мы только объявили, не определили, area()height()или width(). Далее мы создадим файл реализации модуля.

Создание файла реализации единицы модуля

Файлы реализации модуля не заканчиваются расширением .ixx — они обычные .cpp файлы. Добавьте файл реализации модуля, создав исходный файл с правой кнопкой мыши в Обозреватель решений в исходных файлах, выберите "Добавить>новый элемент" и выберите файл C++ (cpp). Присвойте новому файлу имя BasicPlane.Figures-Rectangle.cpp, а затем нажмите кнопку "Добавить".

Соглашение об именовании файла реализации секции модуля следует соглашению об именовании для секции. Но он имеет .cpp расширение, потому что это файл реализации.

Замените содержимое BasicPlane.Figures-Rectangle.cpp файла следующим:

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; }

Этот файл начинается с module; представления специальной области модуля, называемой глобальным фрагментом модуля. Он предшествует коду именованного модуля и позволяет использовать директивы препроцессора, #includeнапример. Код в фрагменте глобального модуля не принадлежит или экспортируется интерфейсом модуля.

Если вы включаете файл заголовка, обычно его не нужно рассматривать как экспортированную часть модуля. Обычно файл заголовка включается в качестве сведений о реализации, которые не должны быть частью интерфейса модуля. Могут возникнуть сложные случаи, когда вы хотите сделать это, но, как правило, вы этого не делаете. Отдельные метаданные (.ifc файлы) не создаются для #include директив в фрагменте глобального модуля. Глобальные фрагменты модуля обеспечивают хорошее место для включения файлов заголовков, таких как windows.h, или в Linux. unistd.h

Файл реализации модуля, который мы создаем, не включает библиотеки, так как они не нужны в рамках его реализации. Но если бы это было, это область, где #include будут идти директивы.

Строка module BasicPlane.Figures:Rectangle; указывает, что этот файл является частью именованного модуля BasicPlane.Figures. Компилятор автоматически переносит типы и функции, предоставляемые основным интерфейсом модуля в этот файл. Единица реализации модуля не имеет export ключевое слово перед module ключевое слово в объявлении модуля.

Далее приведены определения функций area(), height()а также width(). Они были объявлены в Rectangle разделе BasicPlane.Figures-Rectangle.ixx. Так как основной интерфейс модуля для этого модуля импортировал Point секции и Rectangle секции модулей, эти типы отображаются здесь в файле реализации модуля. Интересная функция единиц реализации модуля: компилятор автоматически делает все в соответствующем основном интерфейсе модуля видимым для файла. Нет imports <module-name> необходимости.

Все, что вы объявляете в модуле реализации, видно только модулю, к которому он принадлежит.

Импорт модуля

Теперь мы будем использовать определенный модуль. Откройте файл ModulesTutorial.cpp. Он был создан автоматически в рамках проекта. В настоящее время он содержит функцию main(). Замените его содержимое следующим:

#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;
}

import BasicPlane.Figures; Инструкция делает все экспортированные функции и типы из BasicPlane.Figures модуля видимыми для этого файла. Он может поступать до или после любых #include директив.

Затем приложение использует типы и функции из модуля для вывода области и ширины определенного прямоугольника:

area: 50
width: 10

Составляющие кода модуля

Теперь рассмотрим более подробные сведения о различных файлах модулей.

Основной интерфейс модуля

Модуль состоит из одного или нескольких файлов. Один из них определяет интерфейс, который будет видеть импортеры. Этот файл содержит основной интерфейс модуля. Для каждого модуля может быть только один основной интерфейс модуля. Как отмечалось ранее, экспортируемая единица интерфейса модуля не указывает секцию модуля.

По умолчанию он имеет .ixx расширение. Однако исходный файл можно рассматривать как файл интерфейса модуля с любым расширением. Чтобы сделать это, задайте свойство "Компилировать как как" на вкладке "Дополнительно " для страницы свойств исходного файла значение "Скомпилировать как модуль " (/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

Базовым описанием файла определения интерфейса модуля является:

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.

Этот файл должен начинаться либо с указания начала глобального фрагмента модуля, либо module;export module [module-name]; для указания начала модуля purview.

Модуль purview — это место, где функции, типы, шаблоны и т. д., перейдите к тому, что вы хотите предоставить из модуля.

Кроме того, вы можете предоставлять другие модули или секции модулей с помощью export import ключевое слово, как показано в BasicPlane.Figures.ixx файле.

Файл первичного интерфейса должен экспортировать все секции интерфейса, определенные для модуля напрямую или косвенно, или программа не сформирована.

Раздел частного модуля — это место, в котором можно поместить вещи, которые вы хотите видеть только в этом файле.

Единицы интерфейса модуля предусловлили ключевое слово module с помощью ключевое словоexport.

Дополнительные сведения о синтаксисе модуля см. в разделе "Модули".

Единицы реализации модуля

Единицы реализации модуля принадлежат именованным модулю. Именованный модуль, к которому они относятся, указывается module [module-name] инструкцией в файле. Единицы реализации модуля предоставляют сведения о реализации, которые, по соображениям гигиены кода или других причин, не нужно помещать в основной интерфейс модуля или в файл секционирования модуля.

Единицы реализации модуля полезны для разбиения большого модуля на небольшие части, что может привести к более быстрому времени сборки. Этот метод кратко рассматривается в разделе "Рекомендации ".

Файлы единиц реализации модуля имеют .cpp расширение. Базовым описанием файла единицы реализации модуля является:

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

Файлы секционирования модуля

Секции модулей предоставляют способ компонентизации модуля в разные части или секции. Секции модулей предназначены для импорта только в файлах, которые являются частью именованного модуля. Их нельзя импортировать за пределы именованного модуля.

Раздел содержит файл интерфейса и ноль или более файлов реализации. Раздел модуля предоставляет общий доступ ко всем объявлениям во всем модуле.

Все имена, экспортированные файлами интерфейса секционирования, должны быть импортированы и повторно экспортированы (export import) по файлу первичного интерфейса. Имя раздела должно начинаться с имени модуля, за которым следует двоеточие, а затем имя секции.

Базовая структура файла интерфейса секционирования выглядит следующим образом:

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

Рекомендации по модулю

Модуль и код, импортируемый им, должны быть скомпилированы с теми же параметрами компилятора.

Именование модуля

  • Вы можете использовать периоды ('.') в именах модулей, но они не имеют особого значения для компилятора. Используйте их для передачи смысла пользователям модуля. Например, начните с библиотеки или верхнего пространства имен проекта. Завершите работу с именем, описывающим функциональные возможности модуля. BasicPlane.Figures предназначен для передачи API для геометрических плоскостей, а именно цифры, которые могут быть представлены на плоскости.
  • Имя файла, содержащего основной интерфейс модуля, обычно является именем модуля. Например, учитывая имя BasicPlane.Figuresмодуля, имя файла, содержащего первичный интерфейс, будет названо BasicPlane.Figures.ixx.
  • Имя файла секционирования модуля обычно <primary-module-name>-<module-partition-name> находится в том месте, где за именем модуля следует дефис ('-), а затем имя секции. Например BasicPlane.Figures-Rectangle.ixx.

Если вы создаете из командной строки и используете это соглашение об именовании для секций модулей, вам не придется явно добавлять /reference для каждого файла секционирования модуля. Компилятор будет искать их автоматически на основе имени модуля. Имя скомпилированного файла секции (заканчивается .ifc расширением) создается из имени модуля. Рассмотрим имя BasicPlane.Figures:Rectangleмодуля: компилятор ожидает, что соответствующий скомпилированный файл секции для Rectangle именован BasicPlane.Figures-Rectangle.ifc. Компилятор использует эту схему именования, чтобы упростить использование секций модулей, автоматически найдя файлы единиц интерфейса для секций.

Их можно назвать с помощью собственного соглашения. Но затем необходимо указать соответствующие /reference аргументы компилятору командной строки.

Модули факторов

Используйте файлы реализации модуля и секции, чтобы учитывать модуль для упрощения обслуживания кода и потенциально более быстрого времени компиляции.

Например, перемещение реализации модуля из файла определения интерфейса модуля и в файл реализации модуля означает, что изменения в реализации не обязательно вызывают повторную компиляцию каждого файла, импорта модуля (если у вас нет inline реализаций).

Секции модулей упрощают логический фактор большого модуля. Их можно использовать для улучшения времени компиляции, чтобы изменения в части реализации не приводили к повторной компиляции всех файлов модуля.

Итоги

В этом руководстве вы ознакомились с основами модулей C++20. Вы создали первичный интерфейс модуля, определили секцию модуля и создали файл реализации модуля.

См. также

Обзор модулей в C++
module, , importexport ключевое слово
Обзор модулей C++ в Visual Studio
Практические модули C++20 и будущее инструментов по модулям C++
Перемещение проекта в модули C++ с именем
Пошаговое руководство. Создание и импорт единиц заголовков в Microsoft Visual C++