Включая стиль заголовочных файлов - C++

у меня есть проект, который имеет следующую структуру.

root
--include
----module1
----module2
--src
----module1
----module2

так что foo.cpp на src/module1 должен включать like,

#include "../../include/module1/foo.hpp"

это выглядит грязно и трудно писать. Я нашел записи типа

#include <module1/foo.h>

и предоставление включить путь поиска файлов в root/include при компиляции выглядит аккуратно. Однако я не уверен, что у этого стиля есть какие-то недостатки.

какой из них вы предпочитаете и почему? Также вы видите какие-либо проблемы в организация файлов вышеуказанным способом?

7 ответов


#include "../../include/module1/foo.hpp"

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

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

из моей копии Черновика C++:

файл 16.2 источник включение

2 директива предварительной обработки формы

#include <h-char-sequence> new-line`

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

3 A директива предварительной обработки формы

# include "q-char-sequence" new-line 

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

#include <h-char-sequence> new-line`

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

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


я поддерживаю оба стиля... для различных применений

предположим, у вас также есть каталог root/src/common для целей моего примера

// in src/module1/foo.cpp
#include "module1/foo.h"

#include "../common/stringProcessing.h"

включить

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

кроме того, всегда есть риск использования '..- что она не идет туда, куда вы думали, из-за символической связи, пройденной назад :/

источник

иногда у вас есть заголовки, которые не являются публичными, и, следовательно, не в ):

root
-- include
---- module
------ part1
------ part2
-- src
---- part1
---- part2

и затем вы используете следующую директиву:-I/path../root/include И я ожидаю, что вы создадите либо libmodule.so библиотека module бинарный.


Я предпочитаю 2-й способ

#include <module1/foo.h>

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


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


в качестве небольшого уточнения, я предлагаю вам разрешить cc файлы в модуле1 для доступа к их .h файлы напрямую:

module1/%.cc: -I $ROOT/includes/module1

или аналогичные. Это создаст визуальный эффект в ваших файлах c, который отличает внешние включения от стандартных:

// module1/abc.cc
#include <abc.h>
#include <module2/def.h>

руководство Google по стилю C++ имеет раздел на этом, где они обсуждают порядок и именование включает. Это в основном согласуется с тем, что было сказано в других ответах до сих пор, но стоит взглянуть, поскольку это очень конкретно.

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

Что касается разделения исходных файлов и включения файлов в два разных под-дерева: почему бы не иметь заголовки рядом с исходными файлами? Это облегчает их сопоставление. Если вы не ожидаете, что другие проекты будут использовать ваши заголовки и просто ссылаться на ваши двоичные файлы, я думаю.
- пожми плечами!--3-->


Я не использую пути в #include директивы. По моему опыту, они всегда вызывают проблемы на этапе обслуживания. Многие компиляторы позволяют указать дерево поиска для файлов заголовков.

Файлы Могут Перемещаться

Они будут. Ваша иерархия изменится. Вы можете поместить файлы на другой диск. Они могут изменить местоположение, когда другой пользователь изменяет ваш код. Файлы могут перемещаться, когда они переносятся для другого проекта. Ничто не мешает вам файлы с переезда.

Перемещение Файлов Без Их Изменения

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

на мой взгляд, пути в #include директивы-это зло. Люди, которые это делают, должны быть переподготовлены или отправлены в другие компании.