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

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

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

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

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

Edit:

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

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

Другие предложения очень приветствуются!

Ответ 1

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

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

Ответ 2

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

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

Ответ 3

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

Ответ 4

Наверное, нет. См. сообщение Эрика Липперта по теме.

Пара здесь:

  • Эрик Липперт - разработчик С#, но здесь он говорит о плохом иерархическом дизайне.
  • Многое из того, что описывается в этой статье, связано с присвоением имени классу той же самой вещи, что и пространство имен в С#, но многие из тех же ошибок относятся к С++.

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

Ответ 5

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

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

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

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, не являющийся шаблоном, будет присвоен приоритет.