Подтвердить что ты не робот

Почему мы не можем объявить пространство имен внутри класса?

Объявление класса внутри класса допустимо. (Вложенные классы)

Объявление пространства имен внутри класса недопустимо.

Вопрос заключается в следующем: есть ли веская причина (кроме проблем грамматики/синтаксиса c++) запретить объявление пространства имен внутри класса?


Что касается того, почему я хотел бы сделать это, вот пример:

Позвольте иметь базовую делькарацию контейнера двоичного дерева

template<typename Data>
class binary_tree
{
 public:
  ... stuff ....     

 private:
  ... iterators class declaration ...

 public:
  typedef left_depth_iterator_impl     left_depth_iterator;
  typedef right_depth_iterator_impl    right_depth_iterator;
  typedef left_breadth_iterator_impl   left_breadth_iterator;
  typedef right_breadth_iterator_impl  right_breadth_iterator;

  ... stuff ....     

 private:
  Data         data;
  binary_tree* left;
  binary_tree* right;
};

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

template<typename Data>
class binary_tree
{
 public:
  ... stuff ....     

 private:
  ... iterators class declaration ...

 public:
  namespace iterator
  {
    typedef left_depth_iterator_impl     left_depth;
    typedef right_depth_iterator_impl    right_depth;
    typedef left_breadth_iterator_impl   left_breadth;
    typedef right_breadth_iterator_impl  right_breadth;
  }

  ... stuff ....     

 private:
  Data         data;
  binary_tree* left;
  binary_tree* right;
};

Это позволило бы простое использование:

void  function()
{
  binary_tree::iterator::left_depth   it;

  ...stuff...
}

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

Зачем разрешать вложенные классы и запрещать вложенные пространства имен внутри классов? это наследственное бремя?


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

4b9b3361

Ответ 1

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

Что бы вам предложили пространства имен внутри классов? Вы бы скорее сказали binary_tree::iterator::left_depth вместо просто binary_tree::left_depth? Возможно, если у вас было несколько пространств имен внутри, вы используете их, чтобы отличить слова binary_tree::depth_iterator::left и binary_tree::breadth_iterator::right.

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

Ответ 2

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

С++ 11 7.3-p4: Каждое определение пространства имен должно появляться в глобальной области видимости или в области пространства имен (3.3.6).

Что касается определений классов и предложения об объявлении пространства имен внутри, я предлагаю вам...

С++ 11 9.2-p2: Класс считается полностью определенным типом объекта (3.9) (или полным типом) при закрытии} спецификатора класса. В классе-член класса класс считается полным в телах функций, аргументах по умолчанию, спецификациях исключений и инициаторах с выравниванием или равным для нестатических членов данных (включая такие вещи во вложенных классах). В противном случае он считается неполным в пределах своей спецификации класса.

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

Но скрытие в самом начале стандартного определения пространства имен - это возможность его расширения; расширить его из-за отсутствия лучшего термина:

С++ 7.3-p1: Пространство имен является необязательно названным декларативным регионом. Имя пространства имен может использоваться для доступа к объектам, объявленным в этом пространстве имен; то есть членов пространства имен. В отличие от других декларативных областей определение пространства имен может быть разделено на несколько частей одного или нескольких единиц перевода. (выделено мной).

Следовательно, пространство имен внутри класса нарушило бы определение в 7.3-p4. Предполагая, что этого не было, можно было бы объявить пространство имен где угодно, в том числе в классе, но поскольку определение класса формализовано после его закрытия, вы останетесь только с возможностью сделать следующее, если вы поддерживаете соответствие 7.3-p1:

class Foo
{
   namespace bar
   {
       ..stuff..
   }

   .. more stuff ..

   namespace bar
   {
       ..still more stuff..
   }
};

Полезность этой функции, вероятно, обсуждалась в течение 3-секундных секунд до того, как было установлено 7.3-p4 для ее разрешения.

Ответ 3

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

Просто называя все с помощью префиксов producer или consumer (что является моей текущей раздражающей реализацией), я добавляю загрязнение, которое делает код более трудным для чтения. Например. когда все, что принадлежит продюсеру, начинается с producer, для вашего мозга легче читать его, чтобы случайно автокорректировать producerProducerTimer (продюсерскую копию таймера производителя) как producerConsumerTimer (тень производителя потребительского таймера) или consumerProducerTimer (тень потребителя таймера производителя). Отладка, которая занимает больше времени, чем требуется, потому что код больше не сжимается.

Создав вложенный класс /struct:

  • Я мог бы предоставить следующий разработчик, который поддерживает этот код, идею о том, что более одного из них могут/должны быть созданы, скопированы и назначены друг другу в контексте, поэтому теперь вместо того, чтобы просто беспокоиться об именовании, я также к = delete этим вещам.
  • Я мог бы добавить область памяти в контекст со структурным дополнением выравнивания, которое в противном случае не могло бы быть необходимым.
  • Создание всех членов static не является вариантом, поскольку может быть создано несколько контекстов, которым понадобятся собственные переменные состояния производителя/потребителя.
  • Функции такой структуры больше не имеют доступа к другим данным или функциям члена, таким как константы или функции, которые разделяются обеими сторонами, но вместо этого должны принимать эти аргументы как аргументы.

В идеале я хотел бы изменить такие вещи:

rbptr producerPosition;
rbptr consumerPosition;

:

namespace producer
{
    rbptr position;
}
namespace consumer
{
    rbptr position;
}

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

В этом случае желание предназначено исключительно для уменьшения коллизий имен между производителями и потребительскими копиями вещей, а сокращение коллизий именования - это пространство имен. По этой причине я поддерживаю предложение, чтобы иметь возможность объявлять пространства имен внутри классов.

Ответ 4

Это просто не пространство имен. Пространства имен предназначены для того, чтобы существовать ближе к верхнему уровню кода, так что если две разные компании (или базы кода) могут смешивать код друг с другом. На более микроуровне я кодирую как IMAP для доступа по электронной почте, так и SMTP для отправки электронной почты и (может, я очень упрощаю) имеют классы в любом модуле под названием Email, которые совершенно разные, но я мог бы иметь приложение, скажем почтовый клиент, который хочет использовать оба из одного класса, например возможно, он пересылает письма с одной учетной записи на другую. Пространства имен/имена пакетов и т.д. Разрешают это.

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

Ответ 5

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

template<class...types>
struct Namespace {
    namespace Implementation {
        ...
    }
};

// somewhere else

using namespace Namespace<types...>::Implementation;

// use templated stuff.

Лично мне бы понравилась эта функция, но, кажется, спрос на нее недостаточно высок для ее реализации.