Quali spazi dei nomi ci sono e quali sono le regole?


9

Nota: questa domanda riguarda name spaceno namespace.

Lo standard C ++ ha alcuni riferimenti a name space, ma non vedo la definizione di questo. Gli standard affermano che le etichette e le macro si trovano in spazi dei nomi diversi. Tutti gli altri riferimenti a name spacesono nella sezione di compatibilità C / C ++, in questo modo ( bozza corrente ):

Questa è una delle poche incompatibilità tra C e C ++ che può essere attribuita alla nuova definizione dello spazio dei nomi C ++ in cui un nome può essere dichiarato come tipo e come non tipo in un singolo ambito facendo sì che il nome non tipo nasconda digitare il nome e richiedere l'utilizzo delle parole chiave class, struct, union o enum per fare riferimento al nome del tipo. Questa nuova definizione dello spazio dei nomi offre importanti vantaggi notazionali ai programmatori C ++ e aiuta a rendere l'uso dei tipi definiti dall'utente il più simile possibile all'uso dei tipi fondamentali.

Qual è la nuova definizione dello spazio dei nomi ? Dove posso trovarlo nello standard? Quali sono le regole esatte? Le regole sembrano essere più complicate rispetto ai "tipi non nascosti". Ad esempio, questo non viene compilato:

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

Ma questo fa:

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

E questo non si compila neanche:

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

Il punto di vista pratico è che uno spazio dei nomi è una classe singleton con membri interamente pubblici (sottoclassi). Per favore, non
linciarmi

2
@ peterh-ReinstateMonica leggi la domanda (di nuovo)
YSC

FWIW, il tuo link rimanda alle sezioni pertinenti: Subclause interessato: [class.name] [vedi anche [dcl.typedef]] Puoi vedere quelle sezioni per come funzionano le regole.
NathanOliver,

Esistono almeno due spazi dei nomi: uno per le etichette [stmt.label]/1e uno per le macro [cpp]/8.
YSC

1
È in qualche modo interessante (per me) che sia la descrizione che l'esempio mostrino il contrario di ciò che menziona la logica; un nome di tipo che nasconde un nome non di tipo. Dato il progetto di status, mi aspetto che il paragrafo cambi.
molbdnilo,

Risposte:


2

Il termine spazio dei nomi può essere più ben definito nella norma ISO C; citando ISO C11 :

6.2.3 Spazi dei nomi degli identificatori

Se in qualsiasi punto di un'unità di traduzione è visibile più di una dichiarazione di un particolare identificatore, il contesto sintattico chiarisce gli usi che fanno riferimento a entità diverse. Pertanto, esistono spazi dei nomi separati per varie categorie di identificatori, come segue:

  • nomi delle etichette (non chiariti dalla sintassi della dichiarazione e dell'uso delle etichette);
  • i tag di strutture, sindacati ed enumerazioni (chiariti dal seguente any32) delle parole chiave struct, union o enum);
  • i membri di strutture o sindacati; ogni struttura o unione ha uno spazio dei nomi separato per i suoi membri (non chiarito dal tipo dell'espressione usata per accedere al membro tramite l'operatore. o ->);
  • tutti gli altri identificatori, chiamati identificatori ordinari (dichiarati nei dichiaratori ordinari o come costanti di enumerazione).

La nuova definizione dello spazio dei nomi di C ++, tuttavia, non è in alcun modo recente nel tempo ed è stata descritta in [diff.class] / 1 nella sua forma attuale sin dall'introduzione dello standard ISO C ++ nel '98 . Viene sempre e solo menzionato in qualsiasi lunghezza nei contesti per i quali differisce da ISO C, come per [diff.class] / 1 che è citato dal PO.

Afaics dobbiamo ricorrere a ISO C11 / 6.2.3 e combinarlo con [diff.class] / 1 della norma ISO C ++ per una descrizione coerente e completa della (nuova) definizione dello spazio dei nomi di C ++ , meno purghiamo l'ISO Standard C ++ per es. [Basic.scope.hiding] , [class.name] / 2 , [stmt.label] / 1 , [cpp.replace] / 8 e così via per vedere come e dove si applica.

[Class.name] / 2

Una dichiarazione di classe introduce il nome della classe nell'ambito in cui è dichiarata e nasconde qualsiasi classe, variabile, funzione o altra dichiarazione di quel nome in un ambito allegato. [...]

[Stmt.label] / 1

[...] Le etichette hanno il proprio spazio dei nomi e non interferiscono con altri identificatori [...]

[Cpp.replace] / 1

[...] C'è uno spazio dei nomi per i nomi delle macro. [...]


1

In C (6.2.3 Spazi dei nomi degli identificatori) la nozione di spazi dei nomi è definita nel modo seguente.

1 Se più di una dichiarazione di un particolare identificatore è visibile in qualsiasi punto di un'unità di traduzione, il contesto sintattico chiarisce gli usi che fanno riferimento a entità diverse. Pertanto, esistono spazi dei nomi separati per varie categorie di identificatori, come segue:

- nomi delle etichette (non chiariti dalla sintassi della dichiarazione e dell'uso dell'etichetta);

- i tag di strutture, sindacati ed enumerazioni (chiariti dal seguente any32) delle parole chiave struct, union o enum);

- i membri di strutture o sindacati; ogni struttura o unione ha uno spazio dei nomi separato per i suoi membri (non chiarito dal tipo dell'espressione usata per accedere al membro tramite l'operatore. o ->);

- tutti gli altri identificatori, chiamati identificatori ordinari (dichiarati nei dichiaratori ordinari o come costanti di enumerazione).

Ad esempio, un nome di tag di struttura può coincidere con un nome di funzione perché appartengono a spazi dei nomi diversi. Quando si specifica una struttura con un nome di tag di struttura quando è necessario utilizzare la parola chiave struct. Quindi, ad esempio, queste dichiarazioni non sono in conflitto.

struct s
{
    int s;
};

void s( void );

struct s s1;

In questo snippet di codice il nome sdel tag della struttura non è in conflitto con il nome della funzione s perché il nome del tag deve essere specificato con la parola chiave struct.

In C ++ puoi usare i nomi dei tag di struttura senza la parola chiave struct.

Per esempio

struct s
{
    int s;
};

s s;

è un codice corretto. In questa dichiarazione

s s;

il nome dell'identificatore dichiarato snasconde il nome della struttura. Quindi se scriverai per esempio

s s1;

quindi il compilatore genererà un errore perché in questa istruzione s viene considerato il nome dell'identificatore dichiarato sopra. Per risolvere l'ambiguità è necessario utilizzare la parola chiave struct

struct s
{
    int s;
};

s s;

struct s s1;

Questo è descritto nella seguente citazione dallo standard C ++ 20 (6.3.1 Regioni e ambiti dichiarativi)

4 Dato un insieme di dichiarazioni in un'unica regione dichiarativa, ognuna delle quali specifica lo stesso nome non qualificato,

(4.1) - devono tutti riferirsi alla stessa entità, oppure tutti fare riferimento a funzioni e modelli di funzione; o

(4.2) - esattamente una dichiarazione deve dichiarare un nome di classe o un nome di enumerazione che non sia un nome dattiloscritto e le altre dichiarazioni devono tutte fare riferimento alla stessa variabile, membro di dati non statico o enumeratore, oppure tutti fanno riferimento a funzioni e modelli di funzione ; in questo caso il nome della classe o il nome dell'enumerazione è nascosto (6.3.10). [ Nota: un nome di spazio dei nomi o un nome di modello di classe deve essere univoco nella sua area dichiarativa (10.3.2, clausola 17). - nota finale ]

Come puoi vedere dalla citazione, il nome di uno spazio dei nomi deve essere unico nella sua regione dichiarativa. Quindi queste dichiarazioni

struct Foo { };
namespace Foo { } 

sono errati.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.