Was ist der Umfang der "using" -Deklaration in C ++?

100

Ich verwende die 'using'-Deklaration in C ++, um dem lokalen Namespace std :: string und std :: vector hinzuzufügen (um unnötige' std :: 's einzugeben).

using std::string;
using std::vector;

class Foo { /*...*/ };

Was ist der Umfang dieser Erklärung? Wenn ich dies in einem Header mache, werden diese 'using'-Deklarationen in jede cpp-Datei eingefügt, die den Header enthält?

Jeff Lake
quelle
18
Nur für den Fall, dass dies aus den anderen Antworten hier nicht klar hervorgeht: - Fügen Sie keine usingDeklaration (oder usingDirektive) in den Dateibereich einer Include-Datei / eines Include-Headers ein! Dies bereitet den Benutzern des Headers Kopfschmerzen.
Michael Burr
In der Tat, stellt keine usingErklärung (erst recht Richtlinie ) in einem Header überhaupt , sogar innerhalb eines Namespace! Informationen zu den dadurch verursachten Problemen finden Sie im Anwendungsbereich der Deklaration in einem Namespace .
Nils von Barth
@NilsvonBarth: Das ist ein bisschen vereinfacht. Die Verwendung usingim Klassen- und Funktionsumfang ist in Bezug auf das besprochene Problem sicher.
Sebastian Mach
Vielleicht möchten Sie mehr über die ADL C ++ - Suchfunktion erfahren .
Alexis Wilke

Antworten:

59

Wenn Sie eine Header-Datei in C ++ einschließen, wird der gesamte Inhalt der Header-Datei an der Stelle platziert, an der Sie sie in die Quelldatei aufgenommen haben. Das Einfügen einer Datei mit einer usingDeklaration hat also genau den gleichen Effekt, usingwenn die Deklaration oben in jeder Datei platziert wird, die diese Header-Datei enthält.

Jeremy Ruten
quelle
51
... was im Allgemeinen eine schlechte Sache ist.
Catskul
17
Wenn Sie die usingDeklaration jedoch in a namespaceeinfügen, ist sie auf den Umfang dieses Namespace beschränkt und daher im Allgemeinen in Ordnung (mit den üblichen Einschränkungen für Ihre speziellen Anforderungen und Ihren Stil).
Null
1
... aber wenn Sie die Verwendung in einen Namespace einfügen, stellen Sie sicher, dass Sie nicht versuchen, etwas zu umgehen, das normalerweise eine schlechte Idee ist, da Sie Klassenmethoden, die außerhalb des Namespace Y deklariert sind, nicht in den anderen einschließen können Namespace X, nur damit Sie den Namespace X lokal verwenden können. Deshalb haben wir in erster Linie Namespace :: Resolver verwendet. Wenn es ein so großes Problem beim Tippen ist, entweder ein Makro (das leicht zu Code-Gerüchen führen kann) oder noch besser, isolieren Sie es in seine eigene Quelle .cpp, wo Sie nur den Namespace dort verwenden.
Osirisgothra
1
Diese und ähnliche Antworten sind zwar gute Ratschläge, beantworten die Frage jedoch nicht.
Emile Cormier
116

Es gibt nichts Besonderes an Header-Dateien, das die usingDeklaration fernhalten würde . Es ist eine einfache Textersetzung, bevor die Kompilierung überhaupt beginnt.

Sie können eine usingDeklaration auf einen Bereich beschränken:

void myFunction()
{
   using namespace std; // only applies to the function's scope
   vector<int> myVector;
}
Finsternis
quelle
12
Ich hätte nie gedacht, dass ich es in einer Funktion verwenden könnte!
Agostino
1
Ich habe eine Reihe von Namespaces, die alle von einer Datei vom Typ "Konglomerator" verwendet werden, und das Testen von gmock-Einheiten war besonders mühsam, da bei jedem Test Dinge aus einem bestimmten Namespace verwendet wurden und ich dachte, ich müsste jede einzelne Variable qualifizieren. Die Verwendung usinginnerhalb einer Funktion (oder sogar eines gtest- TESTMakros!) Macht mein Leben so viel besser!
Dwanderson
54

Der Umfang der using-Anweisung hängt davon ab, wo sie sich im Code befindet:

  • Es befindet sich oben in einer Datei und hat einen Gültigkeitsbereich in dieser Datei.
  • Wenn dies eine Header-Datei ist, hat sie Gültigkeitsbereich in allen Dateien, die diesen Header enthalten. Im Allgemeinen ist dies " keine gute Idee ", da es unerwartete Nebenwirkungen haben kann
  • Andernfalls hat die using- Anweisung einen Gültigkeitsbereich innerhalb des Blocks, der sie vom Zeitpunkt ihres Auftretens bis zum Ende des Blocks enthält. Wenn es innerhalb einer Methode platziert wird, hat es Gültigkeitsbereich innerhalb dieser Methode. Wenn es in eine Klassendefinition eingefügt wird, hat es einen Gültigkeitsbereich innerhalb dieser Klasse.
Dagorym
quelle
5
Ich dachte, es wäre nicht möglich, eine usingAnweisung innerhalb des Klassenbereichs hinzuzufügen ...? Aus diesem Grund hatte ich die gleiche Frage wie das OP, da ich vermeiden wollte, std::überall zu tippen . Ich habe Klassen, die viele Vektoren mit intelligenten Zeigern verwenden, und das std::Präfix mit fünf Zeichen fügt viel Zeilenlänge hinzu - was ich als schlechter empfinde. Ich habe mich also gefragt, ob eine usingDirektive im Namespace, die die Klasse enthält, in Ordnung ist. (Auch wenn innerhalb eines Headers.)
thomthom
5
Was ist, wenn es in den Bereich von a gestellt wird namespace { ... }?
Einpoklum
Sie können also vollständig schreiben: {using namespace blabla; Klasse bla {}; } und dass using nur für die Klasse gilt?
Dinaiz
8

Der Gültigkeitsbereich ist der Gültigkeitsbereich, in dem sich die using-Deklaration befindet.

Wenn dies ein globaler Bereich ist, liegt dieser im globalen Bereich vor. Wenn es sich im globalen Bereich einer Header-Datei befindet, befindet es sich im globalen Bereich jeder Quelldatei, die den Header enthält.

Der allgemeine Rat ist daher, die Verwendung von Deklarationen im globalen Bereich von Header-Dateien zu vermeiden .

JohnMcG
quelle
3
Das ist nicht stark genug. Ersetzen Sie vermeiden durch Don't
Martin York
1
Aber vermeiden ist stärker als nicht. "Vermeiden Sie es, die anderen Autos zu
treffen
6

Im genannten Fall die Datei ("Übersetzungseinheit"), dh ja, jede Datei, die sie enthält.

Sie können die using-Anweisung auch in die Klasse einfügen. In diesem Fall gilt sie nur für diese Klasse.

Wenn Sie einen Namespace in einem Header angeben müssen, ist es im Allgemeinen oft am besten, alle erforderlichen Bezeichner vollständig zu qualifizieren.

James Curran
quelle
Beachten Sie, dass sich die usingDeklaration in einer Klasse nicht wie außerhalb einer Klasse verhält - z. B. können Sie sie nicht verwenden, coutanstatt std::coutin den Bereich der Klasse zu bringen.
Null
2

Das ist richtig. Der Bereich ist das Modul, das die usingDeklaration verwendet. Wenn Header-Dateien, die ein Modul enthält, usingDeklarationen enthalten, ist der Umfang dieser Deklarationen dieses Modul sowie alle anderen Module, die dieselben Header enthalten.

Ates Goral
quelle
1

Es gibt einige Kommentare, die eher unqualifiziert sind, wenn sie "Nicht" sagen. Das ist zu streng, aber man muss verstehen, wann es in Ordnung ist.

Schreiben using std::stringist niemals in Ordnung. Wenn Sie using ImplementationDetail::Fooin Ihren eigenen Header schreiben und dieser Header deklariert, kann ImplementationDetail :: Foo in Ordnung sein, auch wenn die using-Deklaration in Ihrem Namespace erfolgt. Z.B

namespace MyNS {
    namespace ImplementationDetail {
        int Foo;
    }
    using ImplementationDetail::Foo;
}
MSalters
quelle
1
Der Benutzer des Headers kann dann schreibenMyNS::Foo
Peter Remmers
Ein besseres Beispiel ist using boost::posix_time::ptime. Sicher, der Benutzer könnte schreiben, MyNS::ptimeaber das ist nicht das Ende der Welt und könnte durch die Bequemlichkeit ausgeglichen werden, Funktionen wie zu haben MyFunction(ptime a, ptime b).
Null
5
Warum ist das using std::stringnie in Ordnung? Auch in Ihrem eigenen Namespace, um viele std::Präfixe zu speichern ?
thomthom
@thomthom es ist in Ordnung, wenn es in einen Bereich wie Ihren eigenen Namespace eingeschlossen ist.
Jcoffland