Jakie są przestrzenie nazw i jakie są zasady?

9

Uwaga: to pytanie dotyczy name space, a nie namespace.

Standard C ++ zawiera kilka odniesień name space, ale nie widzę jego definicji. Według standardów etykiety i makra znajdują się w różnych przestrzeniach nazw. Wszystkie pozostałe odniesienia name spaceznajdują się w sekcji kompatybilności z C / C ++, takie jak ten ( aktualny projekt ):

Jest to jedna z niewielu niezgodności między C i C ++, którą można przypisać nowej definicji przestrzeni nazw C ++, w której nazwę można zadeklarować jako typ i jako nietyp w jednym zakresie, co powoduje, że nazwa nietypowa ukrywa nazwę wpisz nazwę i wymagając użycia słowa kluczowego klasa, struct, union lub enum w celu odniesienia do nazwy typu. Ta nowa definicja przestrzeni nazw zapewnia programistom C ++ ważne notacyjne ułatwienia i pomaga maksymalnie wykorzystać typy zdefiniowane przez użytkownika do podstawowych typów.

Czym jest ta nowa definicja przestrzeni nazw ? Gdzie mogę to znaleźć w standardzie? Jakie są dokładne zasady? Reguły wydają się bardziej skomplikowane niż „typy ukryte inne niż typy”. Na przykład to się nie kompiluje:

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

Ale to powoduje:

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

I to się nie kompiluje:

struct Foo { };   // Type
namespace Foo { } // Non-type, but compiler error instead of hiding
geza
źródło
Praktyczny pogląd jest taki, że przestrzeń nazw jest klasą singletonową z członkami publicznymi (podklasy). Proszę nie
zlinczuj
2
@ peterh-ReinstateMonica przeczytaj pytanie (ponownie)
YSC
FWIW, twój link prowadzi do odpowiednich sekcji: Dotknięta klauzula: [nazwa.klasy] [patrz także [dcl.typedef]] Możesz zobaczyć te sekcje, aby zobaczyć, jak działają reguły.
NathanOliver
Istnieją co najmniej dwie przestrzenie nazw: jedna dla etykiet [stmt.label]/1i jedna dla makr [cpp]/8.
YSC
1
To jest dość interesujące (dla mnie), że zarówno opis, jak i przykład pokazują przeciwieństwo tego, o czym mówi uzasadnienie; nazwa typu ukrywająca nazwę inną niż typ. Biorąc pod uwagę status projektu, oczekiwałbym zmiany tego ustępu.
molbdnilo

Odpowiedzi:

2

Przestrzeni nazw termin ten może być jeszcze dobrze znane z normą ISO C; powołując się na ISO C11 :

6.2.3 Przestrzenie nazw identyfikatorów

Jeśli więcej niż jedna deklaracja określonego identyfikatora jest widoczna w dowolnym punkcie jednostki tłumaczeniowej, kontekst syntaktyczny ujednoznacznia zastosowania odnoszące się do różnych jednostek. Istnieją zatem osobne przestrzenie nazw dla różnych kategorii identyfikatorów, jak następuje:

  • nazwy etykiet (niejednoznaczne przez składnię deklaracji i zastosowania etykiety);
  • tagi struktur, związków i wyliczeń (ujednoznacznione przez dowolne32) słów kluczowych struct, union lub enum);
  • członkowie struktur lub związków; każda struktura lub związek ma osobną przestrzeń nazw dla swoich członków (niejednoznaczne według rodzaju wyrażenia używanego do uzyskania dostępu do członka za pośrednictwem operatora. lub ->);
  • wszystkie inne identyfikatory, zwane zwykłymi identyfikatorami (zadeklarowane w zwykłych deklaratorach lub jako stałe wyliczenia).

Nowa definicja przestrzeni nazw C ++ jest jednak w żaden sposób nie ostatnim w czasie , i zostało opisane w [1] / diff.class w obecnej formie od czasu wprowadzenia ISO C ++ standardu w '98 . Jest on wymieniany tylko w dowolnej długości w kontekstach, dla których różni się od ISO C, zgodnie z [klasa różnicowa] / 1 cytowanym przez PO.

Afaics musimy odwołać się do ISO C11 / 6.2.3 i połączyć go z [klasą różnic] / 1 standardu ISO C ++, aby uzyskać spójny i pełny opis (nowej) definicji przestrzeni nazw C ++ , nie przejmując się ISO C ++ Standard dla np. [Basic.scope.hiding] , [class.name] / 2 , [stmt.label] / 1 , [cpp.replace] / 8 itd., Aby zobaczyć, jak i gdzie ma zastosowanie.

[nazwa klasy] / 2

Deklaracja klasy wprowadza nazwę klasy do zakresu, w którym została zadeklarowana, i ukrywa dowolną klasę, zmienną, funkcję lub inną deklarację tej nazwy w obejmującym zakresie. [...]

[stmt.label] / 1

[...] Etykiety mają własną przestrzeń nazw i nie kolidują z innymi identyfikatorami [...]

[cpp.replace] / 1

[...] Istnieje jedna przestrzeń nazw dla nazw makr. [...]

dfri
źródło
1

W C (6.2.3 Przestrzenie nazw identyfikatorów) pojęcie przestrzeni nazw definiuje się w następujący sposób.

1 Jeśli więcej niż jedna deklaracja określonego identyfikatora jest widoczna w dowolnym punkcie jednostki tłumaczeniowej, kontekst syntaktyczny ujednoznacznia zastosowania odnoszące się do różnych jednostek. Istnieją zatem osobne przestrzenie nazw dla różnych kategorii identyfikatorów, jak następuje:

- nazwy etykiet (niejednoznaczne przez składnię deklaracji i zastosowania etykiety);

- znaczniki struktur, związków i wyliczeń (jednoznaczne po dowolnym32) słów kluczowych struct, union lub enum);

- członkowie struktur lub związków; każda struktura lub związek ma osobną przestrzeń nazw dla swoich członków (niejednoznaczne według rodzaju wyrażenia używanego do uzyskania dostępu do członka za pośrednictwem operatora. lub ->);

- wszystkie inne identyfikatory, zwane zwykłymi identyfikatorami (zadeklarowane w zwykłych deklaratorach lub jako stałe wyliczenia).

Na przykład nazwa znacznika struktury może pokrywać się z nazwą funkcji, ponieważ należą one do różnych przestrzeni nazw. Gdy określisz strukturę o nazwie znacznika struktury, gdy będziesz musiał użyć słowa kluczowego struct. Na przykład te deklaracje nie powodują konfliktu.

struct s
{
    int s;
};

void s( void );

struct s s1;

W tym fragmencie kodu nazwa znacznika sstruktury nie powoduje konfliktu z nazwą funkcji, s ponieważ nazwę znacznika należy podać słowem kluczowym struct.

W C ++ możesz używać nazw znaczników struktury bez słowa kluczowego struct .

Na przykład

struct s
{
    int s;
};

s s;

jest poprawnym kodem. W tej deklaracji

s s;

nazwa deklarowanego identyfikatora sukrywa nazwę struktury. SO, jeśli wtedy napiszesz na przykład

s s1;

wtedy kompilator wygeneruje błąd, ponieważ w tym stwierdzeniu s jest uważane za nazwę wyżej zadeklarowanego identyfikatora. Aby rozwiązać niejednoznaczność, musisz użyć słowa kluczowego struct

struct s
{
    int s;
};

s s;

struct s s1;

Jest to opisane w poniższym cytacie ze standardu C ++ 20 (6.3.1 Regiony i zakresy deklaratywne)

4 Biorąc pod uwagę zestaw deklaracji w jednym regionie deklaratywnym, z których każdy określa tę samą niekwalifikowaną nazwę,

(4.1) - wszystkie odnoszą się do tego samego podmiotu lub wszystkie odnoszą się do funkcji i szablonów funkcji; lub

(4.2) - dokładnie jedna deklaracja deklaruje nazwę klasy lub nazwę wyliczenia, która nie jest nazwą typedef, a pozostałe deklaracje odnoszą się do tej samej zmiennej, elementu danych niestatycznych lub modułu wyliczającego, lub wszystkie odnoszą się do funkcji i szablonów funkcji ; w tym przypadku nazwa klasy lub nazwa wyliczenia jest ukryta (6.3.10). [ Uwaga: nazwa przestrzeni nazw lub nazwa szablonu klasy musi być unikalna w swoim regionie deklaratywnym (10.3.2, klauzula 17). - uwaga końcowa ]

Jak widać z cytatu, nazwa przestrzeni nazw musi być unikalna w swoim deklaratywnym regionie. Więc te deklaracje

struct Foo { };
namespace Foo { } 

są nieprawidłowe.

Vlad z Moskwy
źródło