Руководство по именованным модулям (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). Нажмите кнопку «ОК «, чтобы принять изменение.

Базовым описанием файла определения интерфейса модуля является:
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 .
- Имя файла секционирования модуля обычно — находится в том месте, где за именем модуля следует дефис (‘-), а затем имя секции. Например BasicPlane.Figures-Rectangle.ixx .
Если вы создаете из командной строки и используете это соглашение об именовании для секций модулей, вам не придется явно добавлять /reference для каждого файла секционирования модуля. Компилятор будет искать их автоматически на основе имени модуля. Имя скомпилированного файла секции (заканчивается .ifc расширением) создается из имени модуля. Рассмотрим имя BasicPlane.Figures:Rectangle модуля: компилятор ожидает, что соответствующий скомпилированный файл секции для Rectangle именован BasicPlane.Figures-Rectangle.ifc . Компилятор использует эту схему именования, чтобы упростить использование секций модулей, автоматически найдя файлы единиц интерфейса для секций.
Их можно назвать с помощью собственного соглашения. Но затем необходимо указать соответствующие /reference аргументы компилятору командной строки.
Модули факторов
Используйте файлы реализации модуля и секции, чтобы учитывать модуль для упрощения обслуживания кода и потенциально более быстрого времени компиляции.
Например, перемещение реализации модуля из файла определения интерфейса модуля и в файл реализации модуля означает, что изменения в реализации не обязательно вызывают повторную компиляцию каждого файла, импорта модуля (если у вас нет inline реализаций).
Секции модулей упрощают логический фактор большого модуля. Их можно использовать для улучшения времени компиляции, чтобы изменения в части реализации не приводили к повторной компиляции всех файлов модуля.
Итоги
В этом руководстве вы ознакомились с основами модулей C++20. Вы создали первичный интерфейс модуля, определили секцию модуля и создали файл реализации модуля.
Как создать свой модуль на С++
Объясните поподробнее, что вы подразумеваете под словом модуль ? Файл, который отдельно компилируется (из исходного текста на C++) или динамически загружаемую разделяемую библиотеку или что-то еще ?
7 ноя 2011 в 12:18
2 ответа 2
Сортировка: Сброс на вариант по умолчанию
Мне кажется, вместо того, чтобы задавать такие вопросы пачками, лучше всего взять какую-либо хорошую книжку по C++ и начать по ней заниматься.
Просто то, что на такие вопросы вам ответят здесь, будет, скорее, лишь некоторым частичным пересказом сути, может быть, даже неправильным.
Про один из возможных подходов к изучению C++ с соответствующими книгами можете посмотреть здесь.
Отслеживать
ответ дан 3 ноя 2011 в 1:09
M. Williams M. Williams
23.6k 1 1 золотой знак 41 41 серебряный знак 58 58 бронзовых знаков
поддерживаю
7 ноя 2011 в 11:59
я всецело поддерживаю мнение Котика,которыйхочет_кушать
но если это всерьёз надо, то модули в C++ называются заголовочные файлы и пишутся очень просто(в отдельный файл добавляется нужный вам код, файл помещается в ту-же папку, что и исходный код программы(притом он должен иметь англ. название и расширение .h, .hpp), а в самой программе пишется #include «header.h» именно в кавычках и именно с расширением).
о том, что писать в самом файле не поленитесь почитать специальную литературу.
Отслеживать
ответ дан 7 ноя 2011 в 12:03
1,823 5 5 золотых знаков 28 28 серебряных знаков 40 40 бронзовых знаков
Не путайте человека. Заголовочные файлы и модули — это совсем разные вещи.
7 ноя 2011 в 12:05
простите, но я так понял вопрос-я подумал, что вопрос о модулях, которые хедеры в С++, но модули в паскале.
Программирование по модулям в СИ
Программирование – это процедура написания утилит и софта для разного рода консолей. Существуют различные методы и концепции соответствующего процесса. Вести разработку можно на кроссплатформенных и нативных языках.
Огромную популярность обрело СИ-семейство. Пример – C. Этот язык относительно прост и удобен для понимания. Он предусматривает так называемое модульное программирование. Далее речь зайдет о подобном способе написания софта.
Понятие
Модульное программирование – своеобразная организация утилиты (программного обеспечения) в виде связи независимых блоков, которые носят название модулей. Структура и поведение оных будут подчиняться конкретным принципам и алгоритмам.
Мо дульное программи рование – особый принцип коддинга, при котором отдельные компоненты (блоки) предельно изолированы друг от друга. Детали одного модуля не будут оказывать никакого влияния на реализацию другого. Получить подобного рода результат удастся получить посредством интерфейсов. Возможны и иные виды представления, через которые нельзя получить прямой доступ к кодификации.
Способы реализации
Модульное программирование c, как и в любом другом языке, предусматривает несколько способом реализаций. В зависимости от них будут меняться принципы применения тех или иных функций:
- Установка зависимости. В данной ситуации каждый элемент будет обладать собственным интерфейсом. Модули взаимодействуют посредством interfaces.
- Фабричный прием. Базируется на существовании некоторого объекта, который необходим для создания других. В приложение внедряется прототип, объединяющие ключевые черты для большинства функций. Параметры здесь будут наследоваться от «завода».
- Сервисный подход. Программист должен сделать общий единый интерфейс. Он послужит для функций и их взаимодействия своеобразным буфером.
Первый вариант встречается чаще остальных. Но их тоже необходимо применять на практике. Связано это с тем, что элементарное создание интерфейсов создает ограничения доступа к модулям. Чтобы снизить сложность приложения, требуется уменьшить имеющиеся связи. Функции и интерфейсы, ссылаемые на себе подобные, делают данный процесс сложнее.
Требования к модулям
В программируемом приложении при использовании модулей необходимо учитывать некоторые требования. Без них написать софт, который будет работать по задумке, не представляется возможным.
Модуль – это своеобразная последовательность логически связанных фрагментов (функций), которые оформлены в виде самостоятельных утилитных блоков. А вот требования, которые к нему предъявляются:
- Должен отвечать только за одну единственную функцию. При построении модуля применяется концепция «один блок – одна функция». Отвечает за самостоятельную задачу. На входе можно передать определенных набор исходных материалов, обработать их в соответствие с техническим заданием, а потом возвратить результат обработки.
- Ссылка осуществляется через специализированное имя. Он должен обладать всего одним входом и выходом. Это гарантирует замкнутость «блока».
- Функции должны выступать в виде завершенных алгоритмов.
- Модуль должен передавать управление в точку первоначального вызова. Тут должна присутствовать возможность самостоятельного вызова других «обособленных функций».
- История вызовов не должна сохраняться. Она же не применяется при функционировании «блока кода».
- Логическая независимость. Результат программируемого модуля находится в зависимости от исходных материалов. От других функций утилиты – нет.
- Наличие слабых информационных связей с иными «блоками» утилиты. Обмен информацией производится редко. От предельно минимизирован.
- Модуль C должен быть относительно небольшой. Это касается и его размера, и сложности. Опытные разработчики стараются создавать не более двух страничек печатного текста.
Для того, чтобы обеспечить «блоку» соответствующие критерии, нужно применять принципы информационной локализованности. Смысл его заключается в том, что все электронные материалы о структуре данных, прототипах, константах и функций «прячется» в пределах «готового блока кода». Доступ предоставляется лишь через соответствующий модуль. В СИ-семействе они легко различимы. Обладают расширением .*h.
Как выделить
При работе с рассматриваемым объектом в СИ требуется запомнить, что он состоит из реализации и заголовочного файла. Первый имеет документ вида .c, второй — .h.
Код, который отвечает за подключение «блока», будет на этапе компиляции нуждаться только в интерфейсе. При предпроцессинге заголовочный документ просто копируется в кодификацию директивой #include “somelib.h”
Реализация должна обязательно полностью воплощать в жизнь задуманный интерфейс. Благодаря этому она будет включать тоже свой файл заголовка. Вот пример того, как проект из одного ключевого документа и «блока» будет выглядеть в редакторе:

Это – база, которую может и должен знать каждый разработчик. Программу при помощи рассмотренной концепции создать не составит никакого труда. Особенно если заранее продумать ее структуру и логику.
На что обратить внимание
Приведенный пример предусматривает следующие особенности:
- В документе «мейн.с» не нужно подключать «стдио.h». Это несмотря на то, что он применяется в hello.c.
- Данный момент связан с тем, что никакие типы из stdio не требуются для того, чтобы обрабатывать интерфейс hello.h, который оказывается в «мейне» в процессе компилирования.
- Если бы требовалось для обработки interfaces «блоков» брать определения из той или иной библиотеки, последние должны прописывается не в hello.c, а в hello.h. Данный примем обеспечивает отсутствие ошибок в тех пространствах, где подключается hello.
Это – то, что нужно помнить о модульном программировании C. Информация поможет начать более глубокое изучение концепции.
Лучшее решение для быстрого понимания темы
Для того, чтобы лучше разбираться в функциях и «изолированности кода» в СИ-семействе рекомендуется закончить специализированные онлайн курсы. Они могут быть пройдены в любое время, когда удобно пользователю.
Есть предложения для новичков в программировании, а также для опытных разработчиков. Пользователи смогут изучать функции СИ-семейства и их особенности. В процессе гарантирована масса практики, сбор портфолио и постоянное кураторство. Пользователи смогут получить по выпуску сертификат, подтверждающий знания в выбранном направлении.
Интересует разработка на C? Обратите внимание на курс «Программист C» в Otus.
Обзор модулей в C++
В C++20 представлены модули. Модуль — это набор файлов исходного кода, скомпилированных независимо от исходных файлов (или более точно, единиц перевода, импортируемых ими).
Модули устраняют или сокращают многие проблемы, связанные с использованием файлов заголовков. Они часто сокращают время компиляции, иногда значительно. Макросы, директивы препроцессора и неэкспортированные имена, объявленные в модуле, не отображаются за пределами модуля. Они не влияют на компиляцию единицы перевода, импортируемой модулем. Модули можно импортировать в любом порядке без проблем с переопределениями макросов. Объявления в импортируемом модуле перевода не участвуют в разрешении перегрузки или поиске имен в импортированном модуле. После компиляции модуля результаты хранятся в двоичном файле, который описывает все экспортированные типы, функции и шаблоны. Компилятор может обрабатывать этот файл гораздо быстрее, чем файл заголовка. И компилятор может повторно использовать его везде, где модуль импортируется в проект.
Модули можно использовать параллельно с файлами заголовков. Исходный файл C++ может использовать import модули и #include файлы заголовков. В некоторых случаях можно импортировать файл заголовка в виде модуля, который быстрее, чем используется #include для обработки с помощью препроцессора. Рекомендуется использовать модули в новых проектах, а не файлы заголовков как можно больше. Для более крупных существующих проектов при активной разработке поэкспериментируйте с преобразованием устаревших заголовков в модули. На основе внедрения зависит от того, получается ли существенное сокращение времени компиляции.
Чтобы контрастировать модули с другими способами импорта стандартной библиотеки, см. раздел «Сравнение единиц заголовков», модулей и предварительно скомпилированных заголовков.
Включение модулей в компиляторе Microsoft C++
Начиная с Visual Studio 2022 версии 17.1, стандартные модули C++20 полностью реализованы в компиляторе Microsoft C++.
Прежде чем он был указан стандартом C++20, корпорация Майкрософт поддерживала экспериментальную поддержку модулей. Компилятор также поддерживает импорт предварительно созданных модулей стандартной библиотеки, описанных ниже.
Начиная с Visual Studio 2022 версии 17.5 импорт стандартной библиотеки в качестве модуля является стандартизованным и полностью реализован в компиляторе Microsoft C++. В этом разделе описывается старый экспериментальный метод, который по-прежнему поддерживается. Сведения о новом стандартизованном способе импорта стандартной библиотеки с помощью модулей см. в статье «Импорт стандартной библиотеки C++ с помощью модулей».
Вы можете использовать функцию модулей для создания модулей с одним разделом и импорта модулей стандартной библиотеки, предоставляемых корпорацией Майкрософт. Чтобы включить поддержку модулей стандартной библиотеки, выполните компиляцию и /experimental:module /std:c++latest . В проекте Visual Studio щелкните правой кнопкой мыши узел проекта в Обозреватель решений и выберите «Свойства«. Установите раскрывающийся список «Конфигурация» на все конфигурации, а затем выберите «Свойства> конфигурации C/C++>Language>Enable C++ Modules (экспериментальные)».
Модуль и код, который использует его, необходимо скомпилировать с теми же параметрами компилятора.
Использование стандартной библиотеки C++ в качестве модулей (экспериментальных)
В этом разделе описывается экспериментальная реализация, которая по-прежнему поддерживается. Новый стандартизованный способ использования стандартной библиотеки C++ в качестве модулей описывается в статье Импорт стандартной библиотеки C++ с помощью модулей.
Импортируя стандартную библиотеку C++ в виде модулей, а не включив ее в файлы заголовков, вы можете ускорить компиляцию в зависимости от размера проекта. Экспериментальная библиотека разделена на следующие именованные модули:
- std.regex предоставляет содержимое заголовка
- std.filesystem предоставляет содержимое заголовка
- std.memory предоставляет содержимое заголовка
- std.threading предоставляет содержимое заголовков , , , , и
- std.core предоставляет все остальное в стандартной библиотеке C++
Чтобы использовать эти модули, добавьте объявление импорта в начало файла исходного кода. Например:
import std.core; import std.regex;
Чтобы использовать модули стандартной библиотеки Майкрософт, скомпилируйте программу с /EHsc помощью параметров и /MD параметров.
Пример
В следующем примере показано простое определение модуля в исходном файле Example.ixx . Расширение .ixx требуется для файлов интерфейса модуля в Visual Studio. В этом примере файл интерфейса содержит определение функции и объявление. Однако вы также можете поместить определения в один или несколько отдельных файлов реализации модуля, как показано в следующем примере.
Инструкция export module Example; указывает, что этот файл является основным интерфейсом для вызываемого Example модуля. Модификатор export f() указывает, что эта функция отображается при импорте Example другой программы или модуля.
// Example.ixx export module Example; #define ANSWER 42 namespace Example_NS < int f_internal() < return ANSWER; >export int f() < return f_internal(); >>
Файл MyProgram.cpp используется import для доступа к имени, экспортируемого Example . Имя пространства имен Example_NS отображается здесь, но не все его члены, так как они не экспортируются. Кроме того, макрос ANSWER не отображается, так как макросы не экспортируются.
// MyProgram.cpp import Example; import std.core; using namespace std; int main() < cout
Объявление import может отображаться только в глобальных область.
Грамматика модуля
module-name :
module-name-qualifier-seq необ. identifiermodule-name-qualifier-seq :
identifier .
module-name-qualifier-seq identifier .module-partition :
: module-namemodule-declaration :
export opt module module-name module-partition opt attribute-specifier-seq opt ;module-import-declaration :
export opt import module-name attribute-specifier-seq opt ;
export opt import module-partition attribute-specifier-seq opt ;
export opt import header-name attribute-specifier-seq opt ;
Реализация модулей
Интерфейс модуля экспортирует имя модуля и все пространства имен, типы, функции и т. д., составляющие общедоступный интерфейс модуля.
Реализация модуля определяет вещи, экспортированные модулем.
В самой простой форме модуль может быть одним файлом, который объединяет интерфейс модуля и реализацию. Вы также можете поместить реализацию в один или несколько отдельных файлов реализации модуля, как .h и .cpp файлы.
Для более крупных модулей можно разделить части модуля на подмодулы, называемые секциями. Каждая секция состоит из файла интерфейса модуля, который экспортирует имя секции модуля. У секции также может быть один или несколько файлов реализации секций. Модуль в целом имеет один основной интерфейс модуля, который является общедоступным интерфейсом модуля. При необходимости он может экспортировать интерфейсы секций.
Модуль состоит из одного или нескольких единиц модуля. Модуль — это единица перевода (исходный файл), содержащая объявление модуля. Существует несколько типов единиц модуля:
- Модуль интерфейса модуля экспортирует имя модуля или имя секции модуля. Модуль интерфейса модуля содержит export module в своем объявлении модуля.
- Модуль реализации модуля не экспортирует имя модуля или имя секции модуля. Как подразумевает имя, он реализует модуль.
- Основной модуль интерфейса модуля экспортирует имя модуля. В модуле должен быть один и только один основной модуль интерфейса модуля.
- Единица интерфейса секционирования модуля экспортирует имя секции модуля.
- Модуль реализации секции модуля имеет имя секции модуля в объявлении модуля, но не export ключевое слово.
Ключевое слово export используется только в файлах интерфейса. Файл реализации может быть import другим модулем, но он не export может никаких имен. Файлы реализации могут иметь любое расширение.
Модули, пространства имен и поиск, зависящие от аргументов
Правила для пространств имен в модулях совпадают с любым другим кодом. Если объявление в пространстве имен экспортируется, то включающее пространство имен (за исключением элементов, которые не экспортируются явным образом в этом пространстве имен), также экспортируется неявно. Если пространство имен экспортируется явным образом, экспортируются все объявления в определении пространства имен.
Когда компилятор выполняет поиск в зависимости от аргументов для разрешения перегрузки в модуле импорта перевода, он рассматривает функции, объявленные в той же единице перевода (включая интерфейсы модулей), где определены тип аргументов функции.
Секции модулей
Раздел модуля аналогичен модулю, за исключением следующих:
- Он разделяет владение всеми объявлениями во всем модуле.
- Все имена, экспортированные файлами интерфейса секционирования, импортируются и экспортируются основным файлом интерфейса.
- Имя раздела должно начинаться с имени модуля, за которым следует двоеточие ( : ).
- Объявления в любом из разделов отображаются во всем модуле.\
- Для предотвращения ошибок с одним определением (ODR) не требуются специальные меры предосторожности. Можно объявить имя (функция, класс и т. д.) в одной секции и определить его в другом.
Файл реализации секции начинается следующим образом и является внутренней секцией с точки зрения стандартов C++:
module Example:part1;
Файл интерфейса секции начинается следующим образом:
export module Example:part1;
Чтобы получить доступ к объявлениям в другой секции, необходимо импортировать его. Но он может использовать только имя секции, а не имя модуля:
module Example:part2; import :part1;
Блок первичного интерфейса должен импортировать и повторно экспортировать все файлы секционирования интерфейса модуля, как показано ниже.
export import :part1; export import :part2;
Основной блок интерфейса может импортировать файлы реализации секций, но не может экспортировать их. Эти файлы не разрешены для экспорта имен. Это ограничение позволяет модулю хранить сведения о реализации внутри модуля.
Модули и файлы заголовков
Файлы заголовков можно включить в исходный файл модуля, поставив директиву #include перед объявлением модуля. Эти файлы считаются в глобальном фрагменте модуля. Модуль может видеть только имена в фрагменте глобального модуля, которые находятся в заголовках, которые он явно включает. Глобальный фрагмент модуля содержит только символы, используемые.
// MyModuleA.cpp #include "customlib.h" #include "anotherlib.h" import std.core; import MyModuleB; //. rest of file
Для управления импортом модулей можно использовать традиционный файл заголовка:
// MyProgram.h import std.core; #ifdef DEBUG_LOGGING import std.filesystem; #endif
Импортированные файлы заголовков
Некоторые заголовки достаточно автономны, что их можно использовать с помощью import ключевое слово. Основное различие между импортированным заголовком и импортированным модулем заключается в том, что все определения препроцессора в заголовке отображаются в программе импорта сразу после инструкции import .
import ; import "myheader.h";