Welche Namensräume gibt es und wie lauten die Regeln?

9

Hinweis: Bei dieser Frage geht es name spacenicht um namespace.

Der C ++ - Standard enthält einige Verweise auf name space, aber ich sehe die Definition dafür nicht. Die Standards besagen, dass sich Beschriftungen und Makros in unterschiedlichen Namensräumen befinden. Alle anderen Verweise auf name spacebefinden sich im Abschnitt zur C / C ++ - Kompatibilität wie folgt ( aktueller Entwurf ):

Dies ist eine der wenigen Inkompatibilitäten zwischen C und C ++, die der neuen C ++ - Namensraumdefinition zugeordnet werden können, bei der ein Name als Typ und als Nicht-Typ in einem einzelnen Bereich deklariert werden kann, wodurch der Nicht-Typ-Name den Namen verbirgt Typname und erfordert, dass die Schlüsselwörter class, struct, union oder enum verwendet werden, um auf den Typnamen zu verweisen. Diese neue Namensraumdefinition bietet C ++ - Programmierern wichtige Notationskomfort und hilft dabei, die Verwendung der benutzerdefinierten Typen der Verwendung grundlegender Typen so ähnlich wie möglich zu machen.

Was ist diese neue Namensraumdefinition ? Wo finde ich es im Standard? Was sind die genauen Regeln? Die Regeln scheinen komplizierter zu sein als "Nicht-Typen verstecken Typen". Das wird nicht kompiliert:

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

Aber das tut:

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

Und das kompiliert auch nicht:

struct Foo { };   // Type
namespace Foo { } // Non-type, but compiler error instead of hiding
geza
quelle
Die praktische Ansicht ist, dass ein Namespace eine Singleton-Klasse mit vollständig öffentlichen Mitgliedern (Unterklassen) ist. Bitte lynchen Sie mich nicht :-)
peterh - Setzen Sie Monica
2
@ peterh-ReinstateMonica las die Frage (wieder)
YSC
FWIW, Ihr Link verweist auf die relevanten Abschnitte: Betroffener Unterabschnitt: [class.name] [siehe auch [dcl.typedef]] In diesen Abschnitten erfahren Sie, wie die Regeln funktionieren.
NathanOliver
Es gibt mindestens zwei Namensräume: einen für Beschriftungen [stmt.label]/1und einen für Makros [cpp]/8.
YSC
1
Es ist (für mich) etwas interessant, dass sowohl die Beschreibung als auch das Beispiel das Gegenteil von dem zeigen, was in der Begründung erwähnt wird; Ein Typname, der einen Nicht-Typnamen verbirgt. Angesichts des Statusentwurfs würde ich erwarten, dass sich dieser Absatz ändert.
Molbdnilo

Antworten:

2

Der Begriff des Namensraums ist möglicherweise in der ISO C-Norm besser verankert. unter Berufung auf ISO C11 :

6.2.3 Namensräume von Bezeichnern

Wenn an einem beliebigen Punkt in einer Übersetzungseinheit mehr als eine Deklaration eines bestimmten Bezeichners sichtbar ist, unterscheidet der syntaktische Kontext Verwendungen, die sich auf verschiedene Entitäten beziehen. Daher gibt es separate Namensräume für verschiedene Kategorien von Bezeichnern wie folgt:

  • Labelnamen (eindeutig durch die Syntax der Labeldeklaration und -verwendung);
  • die Tags von Strukturen, Gewerkschaften und Aufzählungen (eindeutig durch Befolgen von any32) der Schlüsselwörter struct, union oder enum);
  • die Mitglieder von Strukturen oder Gewerkschaften; Jede Struktur oder Vereinigung hat einen separaten Namensraum für ihre Mitglieder (eindeutig durch den Typ des Ausdrucks, mit dem über den Operator. oder -> auf das Mitglied zugegriffen wird).
  • alle anderen Bezeichner, die als gewöhnliche Bezeichner bezeichnet werden (in gewöhnlichen Deklaratoren oder als Aufzählungskonstanten deklariert).

Die neue Namensraumdefinition von C ++ ist jedoch in keiner Weise neu in der Zeit und wurde in [diff.class] / 1 in ihrer aktuellen Form seit der Einführung des ISO C ++ - Standards im Jahr '98 beschrieben . Es wird immer nur in irgendeiner Länge in den Kontexten erwähnt, für die es sich von ISO C unterscheidet, gemäß [diff.class] / 1, das vom OP zitiert wird.

Afaics müssen wir auf ISO C11 / 6.2.3 zurückgreifen und es mit [diff.class] / 1 des ISO C ++ - Standards kombinieren, um eine zusammenhängende und vollständige Beschreibung der (neuen) Namensraumdefinition von C ++ zu erhalten , ohne die ISO zu geißeln C ++ Standard für z. B. [basic.scope.hiding] , [class.name] / 2 , [stmt.label] / 1 , [cpp.replace] / 8 usw., um zu sehen, wie und wo es gilt.

[Klassenname] / 2

Eine Klassendeklaration führt den Klassennamen in den Bereich ein, in dem er deklariert ist, und verbirgt jede Klasse, Variable, Funktion oder andere Deklaration dieses Namens in einem umschließenden Bereich. [...]

[stmt.label] / 1

[...] Labels haben einen eigenen Namensraum und stören andere Bezeichner nicht [...]

[cpp.replace] / 1

[...] Es gibt einen Namensraum für Makronamen. [...]

dfri
quelle
1

In C (6.2.3 Namensräume von Bezeichnern) wird der Begriff der Namensräume folgendermaßen definiert.

1 Wenn an einem beliebigen Punkt in einer Übersetzungseinheit mehr als eine Deklaration eines bestimmten Bezeichners sichtbar ist, werden im syntaktischen Kontext Verwendungen eindeutig unterschieden, die sich auf verschiedene Entitäten beziehen. Daher gibt es separate Namensräume für verschiedene Kategorien von Bezeichnern wie folgt:

- Labelnamen (eindeutig durch die Syntax der Labeldeklaration und -verwendung);

- die Tags von Strukturen, Gewerkschaften und Aufzählungen (eindeutig durch Befolgen von any32) der Schlüsselwörter struct, union oder enum);

- die Mitglieder von Strukturen oder Gewerkschaften; Jede Struktur oder Vereinigung hat einen separaten Namensraum für ihre Mitglieder (eindeutig durch den Typ des Ausdrucks, mit dem über den Operator. oder -> auf das Mitglied zugegriffen wird).

- alle anderen Bezeichner, die als gewöhnliche Bezeichner bezeichnet werden (in gewöhnlichen Deklaratoren oder als Aufzählungskonstanten deklariert).

So kann beispielsweise ein Struktur-Tag-Name mit einem Funktionsnamen übereinstimmen, da sie zu verschiedenen Namensräumen gehören. Wenn Sie eine Struktur mit einem Struktur-Tag-Namen angeben, wenn Sie das Schlüsselwort verwenden müssen struct. So stehen diese Erklärungen beispielsweise nicht in Konflikt.

struct s
{
    int s;
};

void s( void );

struct s s1;

In diesem Codeausschnitt steht der Tag-Name sder Struktur nicht in Konflikt mit dem Funktionsnamen, s da der Tag-Name mit dem Schlüsselwort angegeben werden soll struct.

In C ++ dürfen Sie Struktur-Tag-Namen ohne das Schlüsselwort verwenden struct.

Zum Beispiel

struct s
{
    int s;
};

s s;

ist ein korrekter Code. In dieser Erklärung

s s;

Der Name des deklarierten Bezeichners sverbirgt den Strukturnamen. Also wenn dann schreibst du zum Beispiel

s s1;

dann gibt der Compiler einen Fehler aus, da in dieser Anweisung s als Name des oben deklarierten Bezeichners betrachtet wird. Um die Mehrdeutigkeit aufzulösen, müssen Sie das Schlüsselwort struct verwenden

struct s
{
    int s;
};

s s;

struct s s1;

Dies wird im folgenden Zitat aus dem C ++ 20-Standard (6.3.1 Deklarative Regionen und Bereiche) beschrieben.

4 Bei einer Reihe von Deklarationen in einer einzelnen deklarativen Region, von denen jede denselben unqualifizierten Namen angibt,

(4.1) - Sie beziehen sich alle auf dieselbe Einheit oder alle auf Funktionen und Funktionsvorlagen. oder

(4.2) - Genau eine Deklaration muss einen Klassennamen oder Aufzählungsnamen deklarieren, der kein typedef-Name ist, und die anderen Deklarationen müssen sich alle auf dieselbe Variable, nicht statisches Datenelement oder denselben Enumerator beziehen oder sich alle auf Funktionen und Funktionsvorlagen beziehen ;; In diesem Fall wird der Klassenname oder der Aufzählungsname ausgeblendet (6.3.10). [ Hinweis: Ein Namespace-Name oder ein Klassenvorlagenname muss in seinem deklarativen Bereich eindeutig sein (10.3.2, Abschnitt 17). - Endnote ]

Wie Sie dem Zitat entnehmen können, muss ein Namespace-Name in seiner deklarativen Region eindeutig sein. Also diese Erklärungen

struct Foo { };
namespace Foo { } 

sind falsch.

Vlad aus Moskau
quelle