Модули С++20
В стандарте C++20 модули представляют собой новый способ организации и использования кода, который пришел на смену традиционным включаемым заголовочным файлам. Модули предоставляют следующие преимущества:
- Ускорение сборки, благодаря предкомпиляции модулей.
- Изоляция зависимостей, т.е. исключает проблемы дублирования символов и упрощает инкапсуляцию.
- Четкая структура, что улучшает читаемость и поддержку кода.
Особенности работы с модулями
- Ключевое слово export экспортирует элементы (функции, классы, переменные и т.д.) из модуля.
- Ключевое слово import используется для подключения модулей.
- Файлы .cppm и в VS 2022 .ixx рекомендуемое расширение для файлов модулей.
Модули в C++ делают код более структурированным и сокращают количество проблем, связанных с классическими заголовочными файлами, такими как множественные включения и долгие времена компиляции.
Для работы с модулями в Visual Studio 2022 установите настройки проекта как на картинке ниже.
Убедитесь, что Visual Studio поддерживает модули. Используйте последнюю версию Visual Studio (2022 или новее). Поддержка модулей появилась в Visual Studio начиная с версии 2019 (16.8), но она была экспериментальной и сильно улучшилась в 2022.
Проверьте, что у вас установлены необходимые компоненты:
- компилятор MSVC с поддержкой C++20.
Visual Studio требует корректной структуры и расширений файлов:
- файлы модулей должны иметь расширение .ixx (например, vector.ixx), а не .cppm.
Пример кода
// модуль файл vector2d.ixx
#include <iostream>
export module vector2d;
export class Vector2D {
private:
    double x, y; // Координаты вектора
public:
    // Конструкторы
    Vector2D() : x(0), y(0) {}
    Vector2D(double x, double y) : x(x), y(y) {}
    // Методы доступа
    double get_x() const { return x; }
    double get_y() const { return y; }
    void set_x(double value) { x = value; }
    void set_y(double value) { y = value; }
    // Методы работы с вектором
    double length() const {
        return std::sqrt(x * x + y * y);
    }
    Vector2D normalize() const {
        double len = length();
        if (len == 0) {
            throw std::runtime_error("Cannot normalize a zero-length vector.");
        }
        return Vector2D(x / len, y / len);
    }
    // Операции над векторами
    Vector2D operator+(const Vector2D& other) const {
        return Vector2D(x + other.x, y + other.y);
    }
    Vector2D operator-(const Vector2D& other) const {
        return Vector2D(x - other.x, y - other.y);
    }
    double dot(const Vector2D& other) const {
        return x * other.x + y * other.y;
    }
    // Перегрузка вывода
    friend std::ostream& operator<<(std::ostream& os, const Vector2D& v) {
        os << "(" << v.x << ", " << v.y << ")";
        return os;
    }
};Ключевое слово export указывает, что содержимое этого модуля доступно для других файлов через import.
// файл main.cpp который использует модуль vector2d.ixx
import vector2d; // Импортируем модуль
#include <iostream>
int main() {
    try {
        // Создаём векторы
        Vector2D v1(3.0, 4.0);
        Vector2D v2(1.0, 2.0);
        // Выводим информацию о векторах
        std::cout << "Vector v1: " << v1 << "\n";
        std::cout << "Vector v2: " << v2 << "\n";
        // Выполняем операции
        Vector2D v3 = v1 + v2;
        Vector2D v4 = v1 - v2;
        std::cout << "v1 + v2: " << v3 << "\n";
        std::cout << "v1 - v2: " << v4 << "\n";
        std::cout << "Dot product of v1 and v2: " << v1.dot(v2) << "\n";
        std::cout << "Length of v1: " << v1.length() << "\n";
        Vector2D normalized = v1.normalize();
        std::cout << "Normalized v1: " << normalized << "\n";
    }
    catch (const std::exception& e) {
        std::cerr << "Error: " << e.what() << "\n";
    }
    return 0;
}