Какие существуют пространства имен и каковы правила?

Примечание: этот вопрос касается name space, а не namespace.

В стандарте С++ есть некоторые ссылки на name space, но я не вижу его определения. Стандарты говорят, что метки и макросы находятся в разных пространствах имен. Все остальные ссылки на name space находятся в разделе совместимости с C/C++, например (current черновик):

Это одна из немногих несовместимостей между C и C++, которая может быть связана с новым определением пространства имен C++, где имя может быть объявлено как тип и как нетип в одной области, что приводит к нетиповое имя, чтобы скрыть имя типа и потребовать, чтобы ключевые слова class, struct, union или enum использовались для ссылки на имя типа. Это новое определение пространства имен предоставляет важные удобства для программистов на C++ и помогает максимально приблизить использование определяемых пользователем типов к использованию фундаментальных типов.

Что это за новое определение пространства имен? Где его найти в стандарте? Каковы точные правила? Правила кажутся более сложными, чем «не-типы скрывают типы». Например, это не компилируется:

typedef int Foo; // Foo is a type
void Foo();      // not a type, but compile error, instead of hiding

Но это делает:

struct Foo { }; // Foo is a type as well
void Foo();     // This hides the type Foo. "struct Foo" refers to the type

И это тоже не компилируется:

struct Foo { };   // Type
namespace Foo { } // Non-type, but compiler error instead of hiding

person geza    schedule 17.03.2020    source источник
comment
Практическая точка зрения состоит в том, что пространство имен представляет собой одноэлементный класс со всеми общедоступными членами (подклассами). Пожалуйста, не линчуйте меня :-)   -  person peterh    schedule 17.03.2020
comment
@peterh-ReinstateМоника прочитала вопрос (снова)   -  person YSC    schedule 17.03.2020
comment
FWIW, ваша ссылка ведет на соответствующие разделы: Затрагиваемый подпункт: [class.name] [см. также [dcl.typedef]] Вы можете увидеть эти разделы, чтобы узнать, как работают правила.   -  person NathanOliver    schedule 17.03.2020
comment
Существует как минимум два пространства имен: одно для меток [stmt.label]/1 и одно для макросов < a href="https://eel.is/c++draft/cpp#replace-8" rel="nofollow noreferrer">[cpp]/8.   -  person YSC    schedule 17.03.2020
comment
Один для типов (но пространство имен не отображается дословно): [class.name]/2.   -  person YSC    schedule 17.03.2020
comment
@YSC: Ага. Если бы были другие упоминания о пространстве имен для других вещей, я бы не задавал этот вопрос. Но есть только два обращения к пространству имен (плюс четыре в разделе совместимости с C/C++), отсюда и вопрос.   -  person geza    schedule 17.03.2020
comment
Вот почему я не поместил это в раздел ответов, это не ответ.   -  person YSC    schedule 17.03.2020
comment
@YSC: хорошо :)   -  person geza    schedule 17.03.2020
comment
Несколько интересно (для меня), что и описание, и пример показывают обратное тому, что упоминается в обосновании; имя типа, скрывающее имя, не являющееся типом. Учитывая статус проекта, я ожидаю, что этот пункт изменится.   -  person molbdnilo    schedule 17.03.2020


Ответы (2)


Термин пространство имен может быть более устоявшимся в стандарте ISO C; со ссылкой на ISO C11:

6.2.3 Пространства имен идентификаторов

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

  • имена меток (устраненные синтаксисом объявления и использования метки);
  • теги структур, объединений и перечислений (устраняются неоднозначностью, следуя any32) ключевых слов struct, union или enum);
  • члены структур или союзов; каждая структура или объединение имеет отдельное пространство имен для своих элементов (неоднозначность определяется типом выражения, используемого для доступа к элементу с помощью оператора . или -›);
  • все остальные идентификаторы, называемые обычными идентификаторами (объявленные в обычных деклараторах или как константы перечисления).

Однако новое определение пространства имен в C++ никоим образом не является недавним и было описано в [diff.class] /1 в его текущей форме с тех пор, как ISO Введение стандарта C++ в '98. Он упоминается любой длины только в контексте, в котором он отличается от ISO C, в соответствии с [diff.class]/1, который цитируется OP.

Конечно, нам нужно прибегнуть к ISO C11/6.2.3 и объединить его с [diff.class]/1 стандарта ISO C++ для связного и полного описания (нового) определения пространства имен C++, меньше мы бичуем стандарт ISO C++, например. [basic.scope.hiding], [class.name]/2, [stmt.label]/1, [cpp.replace]/8 и т. д., чтобы узнать, как и где это применяется.

[class.name]/2

Объявление класса вводит имя класса в область, в которой оно объявлено, и скрывает любой класс, переменную, функцию или другое объявление этого имени в охватывающей области. [...]

[stmt.label]/1

[...] Метки имеют собственное пространство имен и не мешают другим идентификаторам [...]

[cpp.replace]/1

[...] Существует одно пространство имен для имен макросов. [...]

person dfrib    schedule 17.03.2020

В C (6.2.3 Пространства имен идентификаторов) понятие пространств имен определяется следующим образом.

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

- имена меток (устраненные синтаксисом объявления и использования метки);

- теги структур, объединений и перечислений (устраняются неоднозначностью, следуя any32) ключевых слов struct, union или enum);

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

— все остальные идентификаторы, называемые обычными идентификаторами (объявленные в обычных деклараторах или как константы перечисления).

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

struct s
{
    int s;
};

void s( void );

struct s s1;

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

В C++ разрешено использовать имена структурных тегов без ключевого слова struct.

Например

struct s
{
    int s;
};

s s;

является правильным кодом. В этой декларации

s s;

имя объявленного идентификатора s скрывает имя структуры. ТАК если то напишешь к примеру

s s1;

то компилятор выдаст ошибку, потому что в этом операторе s рассматривается как имя объявленного выше идентификатора. Чтобы устранить двусмысленность, вам нужно использовать ключевое слово struct

struct s
{
    int s;
};

s s;

struct s s1;

Это описано в следующей цитате из стандарта C++ 20 (6.3.1 Декларативные области и области).

4 Учитывая набор объявлений в одной декларативной области, каждое из которых определяет одно и то же неполное имя,

(4.1) — все они должны относиться к одному и тому же объекту или все относятся к функциям и шаблонам функций; или же

(4.2) — ровно одно объявление должно объявлять имя класса или имя перечисления, которое не является именем typedef, а все остальные объявления должны ссылаться на одну и ту же переменную, нестатический член данных или перечислитель, или все ссылаться на функции и шаблоны функций. ; в этом случае имя класса или имя перечисления скрыто (6.3.10). [ Примечание. Имя пространства имен или имя шаблона класса должно быть уникальным в своей декларативной области (10.3.2, пункт 17). — конец примечания ]

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

struct Foo { };
namespace Foo { } 

неверны.

person Vlad from Moscow    schedule 17.03.2020