Каждый класс должен иметь свое собственное пространство имен?

Что-то, что беспокоило меня некоторое время:

Текущая мудрость - то, что типы должны быть сохранены в пространстве имен, которое только содержит функции, которые являются частью не являющегося членом интерфейса типа (см., что C++ Кодирует Стандарты Sutter и Alexandrescu или здесь), предотвратить получение по запросу ADL в несвязанных определениях.

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

Причина, которую я спрашиваю, состоит в том, что пространства имен становятся громоздкими для меня. Я пишу библиотеку только для заголовка, и я использую имена классов, такие как проект:: компонент:: class_name:: class_name. Их реализации вызывают функции помощника, но поскольку они не могут быть в том же пространстве имен, они также должны быть полностью определены!

Править:

Несколько ответов предположили, что пространства имен C++ являются просто механизмом для предотвращения столкновений имени. Это не так. В функциях C++, которые берут параметр, разрешены с помощью Зависимого Поиска Аргумента. Это означает что, когда компилятор пытается найти функциональное определение, которое соответствует имени функции, это посмотрит на каждую функцию в том же пространстве (пространствах) имен как тип (типы) его параметра (параметров) при нахождении кандидатов.

Это может иметь непреднамеренные, неприятные последствия, как детализировано в Скромном предложении: Фиксация ADL. Sutter и состояния правила Alexandrescu никогда не помещают функцию в то же пространство имен как класс, если оно не предназначено, чтобы быть частью интерфейса того класса. Я не вижу, как я могу соблюсти то правило, если я не готов дать каждому классу его собственное пространство имен.

Больше очень приветствующихся предложений!

11
задан thehouse 1 April 2010 в 23:23
поделиться

5 ответов

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

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

7
ответ дан 3 December 2019 в 02:52
поделиться

Это довольно интересная статья, но тогда, учитывая авторов, была большая вероятность, что это будет. Однако отмечу, что проблема касается в основном:

  • typedef, потому что они вводят только псевдоним, а не новый тип
  • templates

Если я это сделаю:

namespace foo
{
  class Bar;

  void copy(const Bar&, Bar&, std::string);
}

И вызову его:

#include <algorithms>

#include "foo/bar.h"

int main(int argc, char* argv[])
{
  Bar source; Bar dest;
  std::string parameter;
  copy(source, dest, parameter);
}

Тогда он должен выбрать foo::copy. Фактически, он будет рассматривать как foo::copy, так и std::copy, но foo::copy, не являясь шаблоном, будет отдаваться приоритет.

0
ответ дан 3 December 2019 в 02:52
поделиться

Нет, нет и тысячу раз нет! Пространства имен в C++ не являются архитектурными или дизайнерскими элементами. Это просто механизм для предотвращения столкновений имен. Если на практике у вас нет столкновений имен, то пространства имен вам не нужны.

8
ответ дан 3 December 2019 в 02:52
поделиться

Нет. Я никогда не слышал о таком соглашении. Обычно каждая библиотека имеет свое собственное пространство имен, и если эта библиотека имеет несколько различных модулей (например, различных логических единиц, отличающихся по функциональности), то они могут иметь свое собственное пространство имен, хотя достаточно одного пространства имен на библиотеку. В пространстве имен библиотеки или модуля можно использовать пространство имен detail или анонимное пространство имен для хранения деталей реализации. Использование одного пространства имен на класс - это, ИМХО, полный перебор. Я бы определенно воздержался от этого. В то же время, я бы настоятельно рекомендовал вам иметь хотя бы одно пространство имен для вашей библиотеки и размещать все в этом пространстве имен или его подпространстве, чтобы избежать столкновения имен с другими библиотеками.

Чтобы сделать это более конкретным, позвольте мне использовать в качестве примера почтенную библиотеку Boost C++ Libraries. Все элементы внутри boost находятся в boost::. Есть некоторые модули внутри Boost, например, библиотека interprocess, которая имеет собственное пространство имен, например, boost::interprocess::, но по большей части элементы boost (особенно те, которые используются очень часто и в разных модулях) просто находятся в boost::. Если вы посмотрите внутри boost, он часто использует boost::detail или boost::name_of_module::detail для хранения деталей реализации для данного пространства имен. Я предлагаю вам моделировать свои пространства имен таким образом.

15
ответ дан 3 December 2019 в 02:52
поделиться

Вероятно, нет. См. сообщение Эрика Липперта на эту тему.

Здесь есть пара моментов:

  1. Эрик Липперт - дизайнер C#, но то, что он говорит о плохом иерархическом дизайне, применимо и здесь.
  2. Многое из того, что описано в этой статье, связано с именованием класса так же, как пространства имен в C#, но многие из тех же подводных камней применимы и к C++.

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

0
ответ дан 3 December 2019 в 02:52
поделиться
Другие вопросы по тегам:

Похожие вопросы: