Каков наилучший / самый чистый способ использования пространств имен в упакованном коде?
Например. в библиотеках как увеличение похоже, что управление пространствами имен очень организовано, используются некоторые методы, позволяющие устранить неоднозначность имен. Важная вещь, однако, заключается в том, что никто не увидит много кода, как
typedef namespace1::namespace2::sth_else::a_class<namespace3::namespace4::b_class> type;
как правило, между именами не так много пространства, что указывает на хорошую архитектуру, а также хорошее управление пространством имен. Вопрос в том, что такое хорошее управление пространством имен?
Скажем, у нас есть такая структура файлов:
component1/... (depends on reusable_if)
component2/... (depends directly on reusable_if and on component 1)
reusable/
reusable/some_part/
reusable/some_part/...
reusable/some_other_part/
reusable/some_other_part/...
reusable/SthThatUsesBothReusableParts.h (implements reusable_if/ISth.h)
reusable/SthThatUsesBothReusableParts.cpp (implements reusable_if/ISth.h)
reusable_if/
reusable_if/ISth.h (pure abstract class)
reusable_if/ISthElse.h (pure abstract class)
main.cpp (e.g. instantiates SthThatUsesBothReusableParts and passes to component1/2)
Причина, по которой существует папка reusable_if /, заключается в том, что и component1, и component2 хотят повторно использовать одни и те же интерфейсы (следовательно, ни один из них не «владеет» исключительно этими интерфейсами). Кроме того, предполагается, что проект действительно очень большой и нуждается в надлежащих пространствах имен для классов в каждой из папок.
Как бы вы применили пространства имен в таком проекте?
Скажем, я объявляю все классы в пространстве имен многократного использования ::reusable
, Должен ли я поместить интерфейсы из reusable_if в пространство имен ::reusable
или в ::reusable_if
? Или, может быть, в none, так как он используется component1 и component2?
Как насчет пространств имен в component1 и component2? Есть что вспомнить?
Как насчет ключевого слова using
? Допустим, я решил добавить это ::reusable_if
Пространство имен. Можно поставить using reusable_if
в заголовочные файлы в component1 и component2, при условии, что using ...
находится внутри пространства имен ::component1
а также ::component2
?
Я открыт для любых предложений, в том числе не обязательно связанных с приведенным выше примером.
Вот что я использую для своих проектов. Мое главное правило — каждый каталог — это пространство имен, а каждый файл — это класс, за очень немногими исключениями (иногда я группирую вспомогательные функции в подкаталогах пространства имен. detail
, но без другого вложенного пространства имен).
Держите весь ваш проект в едином пространстве имен верхнего уровня, названного в честь вашего проекта.
Храните каждый служебный компонент в пространстве имен верхнего уровня, но в отдельном каталоге. Это единственный раз, когда я не позволяю пространствам имен перекрываться с моим деревом каталогов.
Храните каждый независимо выпускаемый компонент в вашем проекте во вложенном пространстве имен, названном в честь вашего компонента. Для удобства предоставьте один заголовок, названный в честь вашего компонента и содержащий весь интерфейс компонента, либо в каталоге, соответствующем вашему пространству имен, либо непосредственно в каталоге верхнего уровня вашего проекта.
Хранить реализацию каждого компонента во вложенном пространстве имен detail
, В отличие от классов, пространство имен не имеет языковой поддержки для private
члены, но соглашение в Boost заключается в том, что пространство имен detail
не должен напрямую вызываться кодом пользователя.
Нет дальнейшего вложения, чем project::component::detail::function()
или же project:::component::class.member()
необходимо. Если вы предоставляете полные интерфейсы, которые облегчают ADL, вы можете повторно использовать функции компонентов внутри вашего проекта как function(x)
для переменной x
типа project::component::class
не беспокоясь о столкновении имен.
Обратите внимание, что на языке дяди Боба: «единица повторного использования является единицей выпуска«. Каждый компонент должен обеспечивать связку взаимосвязанных и взаимозависимых классов и функций. В частности, он должен обеспечивать полный интерфейс для этого компонента. Язык C ++ будет поддерживать это через Аргумент-зависимый поиск (ADL). Смотрите эту старую колонкуПространства имен и принцип интерфейса«Хербом Саттером.
Наличие reuse_if
и наличие обоих component
а также reusable
может быть запахом кода, если только соображения, которые вы упомянули в комментариях, на самом деле не применимы. Компонент должен быть единицей выпуска. Если бы вы могли самостоятельно использовать кусок кода, сделайте его отдельным компонентом. Если код зависит от другого куска, выпустите его вместе с этим другим кодом. См. Столбец Саттера для этих отношений зависимости.
Отказ от личного мнения. Ваш вопрос в основном требует субъективных ответов и, вероятно, будет закрыт для него, но я дам ему шанс.
Пространства имен в первую очередь полезны, чтобы избежать столкновений идентификаторов. Есть «ваше» пространство имен (mylib::
) и пространства имен всех остальных (std::
, boost::
, icu::
, …), и это примерно столько, сколько пространства имен должно быть принято.
Вы можете получить небольшую выгоду, поделив ваш проект (например, «проект вашей команды») на подпространства имен, если у вас возникает проблема со столкновением идентификаторов — в этом случае вам следует пересмотреть свою стратегию вызова ваших классов X
а также Y
, 😉
Вещи немного отличаются в огромный libs, как Boost. По сути, они состоят из множества различных проектов, поддерживаемых отдельными командами, поэтому существует проблема конфликтующих друг с другом идентификаторов конкретных проектов, если они все были объединены boost::
(и столкновение, возможно, не обнаруживается в случайном тестировании).
Если вы перестанете смотреть на boost::filesystem
как «подпространство имен», и вместо этого посмотрите на boost::
как «обертка личности» для отдельных проектов filesystem::
, thread::
, program_options::
и еще много чего, так, чтобы они выглядели более «усиленно», картина становится более четкой.