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

9

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

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

Это одна из немногих несовместимостей между 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
Геза
источник
Практическое представление состоит в том, что пространство имен - это одноэлементный класс с общедоступными членами (подклассами). Пожалуйста, не
линчуйте
2
@ peterh-ReinstateMonica прочитайте вопрос (еще раз)
YSC
FWIW, ваша ссылка ссылается на соответствующие разделы: Затрагиваемый подпункт: [class.name] [см. Также [dcl.typedef]] Вы можете увидеть эти разделы о том, как работают правила.
Натан Оливер
Существует как минимум два пространства имен: одно для меток [stmt.label]/1и одно для макросов [cpp]/8.
МСК
1
Мне несколько интересно (как для меня), что и описание, и пример показывают противоположность тому, что упоминается в обосновании; имя типа, скрывающее нетипичное имя. Учитывая проект статуса, я бы ожидал, что этот пункт изменится.
молбднило

Ответы:

2

Пространство имен термин может быть более четко установлена в ISO C стандарт; цитируя ISO C11 :

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

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

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

Новое определение пространства имен из C ++, однако, ни в коей мере недавнего времени , и был описан в работе [diff.class] / 1 в его нынешнем виде когда - либо с момента введения C ++ Стандарта ISO в '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

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

dfri
источник
1

В 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 { } 

неверны.

Влад из Москвы
источник