При использовании модулей C++ имеет ли смысл отделять объявления функций (файлы.hpp) от их определений (файлы.cpp)?

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

// foo.h 
class Foo
{
    void bar();
};

и соответствующий файл.cpp содержит определение:

// foo.cpp
#include "foo.h"

void Foo::bar()
{
    // ...
}

Насколько мне известно, это сделано для уменьшения времени компиляции и уменьшения зависимостей. Когда модули будут использоваться, это все еще будет применяться? Было бы так же быстро разместить класс в одном файле с определениями, как это делают Java и C#? Если это так, будет ли необходимость в обоих .hpp а также .cpp файлы при использовании модулей?

4 ответа

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

Если программа состоит из модулей и не отделяет объявления функций от определений, все файлы модулей будут интерфейсами модулей (в отличие от реализаций модулей). Если вы хотите сравнить их с заголовочными файлами и файлами кода, интерфейсы модуля можно рассматривать как файл заголовка (.hpp), а реализации модуля можно рассматривать как файлы кода (.cpp).

К сожалению, предложение модулей не допускает циклических зависимостей интерфейса модуля. А поскольку ваша программа теперь полностью состоит из интерфейсов модулей, вы никогда не сможете иметь два модуля, которые каким-либо образом зависят друг от друга (это может быть улучшено proclaimed ownership объявление в будущем, но это в настоящее время не поддерживается). Единственный способ разрешить циклические зависимости интерфейса модуля - разделить объявления и определения и поместить циклический импорт в файлы реализации модуля, в отличие от циклических зависимостей интерфейса модуля, допускаются циклические зависимости реализации модуля.

Следующий код предоставляет пример ситуации, которую невозможно скомпилировать без разделения объявлений и определений:

Foo module file

export module Foo;

import module Bar;

export namespace Test {
    class Foo {
    public:
        Bar createBar() {
            return Bar();
        }
    };
}

Bar module file

export module Bar;

import module Foo;

export namespace Test {
    class Bar {
    public:
        Foo createFoo() {
            return Foo();
        }
    };
}

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

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

Есть еще много причин использовать файлы заголовков.

Простота совместного использования и понимания объектного API, не видя базовых деталей, достаточно полезна, чтобы держать их рядом. Это хороший 20-футовый обзор объекта, по сути являющийся контуром.

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

Я не верю, что это возможно без заголовочных файлов.

Здесь есть хорошая дискуссия, которая объясняет идею модулей.

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

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

Использование предварительно скомпилированных заголовков действительно не стало важной вещью, пока расширенное использование заголовочных файлов в C++ не сделало это необходимым по соображениям производительности (несмотря на некоторые очень большие заголовки старой школы, такие как windows.h).

Идея состоит в том, чтобы ввести в игру нечто большее, чем механизм C#/Java. Механизм C++ очень по духу Modula/ADA. Было бы неплохо, чтобы машины делали больше за нас.

Другие вопросы по тегам