Должен ли каждый класс иметь свое собственное пространство имен? - PullRequest
11 голосов
/ 02 апреля 2010

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

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

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

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

Edit:

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

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

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

Ответы [ 5 ]

15 голосов
/ 02 апреля 2010

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

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

8 голосов
/ 02 апреля 2010

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

7 голосов
/ 02 апреля 2010

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

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

0 голосов
/ 02 апреля 2010

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

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

0 голосов
/ 02 апреля 2010

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

Пара вещей здесь:

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

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

...