Дизайн библиотеки только для заголовков — включает директивы

Я создаю библиотеку C ++ 11/14 только для заголовков, и я не уверен, как мне поступить #include директивы между библиотечными файлами.

Должен ли я попытаться сгруппировать как можно больше #include директивы, насколько это возможно, в заголовочном файле модуля, ориентированного на пользователя, или внутренние файлы должны включать файлы, которые им требуются (иногда повторяя те же самые включения)?


Подход А:

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

// Library/Module/Module.hpp
// This file is intended to be included by the user in his projects.

#ifndef MODULE
#define MODULE

#include <vector>
#include "Library/Module/Impl/SharedDependency.hpp"#include "Library/Module/Impl/Class1.hpp"#include "Library/Module/Impl/Class2.hpp"
#endif MODULE

// Library/Module/Impl/SharedDependency.hpp

#ifndef SHARED_DEPENDENCY
#define SHARED_DEPENDENCY

inline void sharedFunc() { }

#endif

// Library/Module/Impl/Class1.hpp

#ifndef CLASS1
#define CLASS1

// No need to include "SharedDependency.hpp", as it will be included by
// the module header file. Same applies for <vector>.
struct Class1
{
std::vector<int> v;
Class1() { sharedFunc(); }
};

#endif

// Library/Module/Impl/Class2.hpp

#ifndef CLASS2
#define CLASS2

// No need to include "SharedDependency.hpp", as it will be included by
// the module header file. Same applies for <vector>.
struct Class2
{
std::vector<int> v;
Class2() { sharedFunc(); }
};

#endif


Подход Б:

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

// Library/Module/Module.hpp
// This file is intended to be included by the user in his projects.

#ifndef MODULE
#define MODULE

#include "Library/Module/Impl/Class1.hpp"#include "Library/Module/Impl/Class2.hpp"
#endif MODULE

// Library/Module/Impl/SharedDependency.hpp

#ifndef SHARED_DEPENDENCY
#define SHARED_DEPENDENCY

inline void sharedFunc() { }

#endif

// Library/Module/Impl/Class1.hpp

#ifndef CLASS1
#define CLASS1

#include <vector>
#include "Library/Module/Impl/SharedDependency.hpp"
struct Class1
{
std::vector<int> v;
Class1() { sharedFunc(); }
};

#endif

// Library/Module/Impl/Class2.hpp

#ifndef CLASS2
#define CLASS2

#include <vector>
#include "Library/Module/Impl/SharedDependency.hpp"
struct Class2
{
std::vector<int> v;
Class2() { sharedFunc(); }
};

#endif

Каков наилучший подход?

Я думаю, что интуитивно Подход А является лучшим, так как он избегает повторения тех же самых включений и проясняет, какие файлы должны быть включены перед другими файлами. Однако самый большой недостаток заключается в том, что подсветка синтаксиса перестает работать в моей IDE (QT-Creator), в файлах реализации без директив include.


РЕДАКТИРОВАТЬ:

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

2

Решение

Подход Б на самом деле является лучшим подходом, поскольку многократное включение одного и того же заголовка не приводит к заметному увеличению времени компиляции, но выгодно по следующим причинам:

  • Современные IDE могут использовать libclang или запатентованные решения для разбора #include директивы и предоставляют функции подсветки синтаксиса и автозаполнения с учетом кода.

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

  • Как уже упоминал Альф, хорошей практикой является включение в каждый файл всех заголовков, от которых он зависит — пользователи библиотеки могут затем «выбирать файлы заголовков», которые им требуются, вместо неожиданного принудительного включения родительского заголовка вручную.

0

Другие решения


По вопросам рекламы [email protected]