Qual è lo scopo della dichiarazione "using" in C ++?


100

Sto usando la dichiarazione "using" in C ++ per aggiungere std :: string e std :: vector allo spazio dei nomi locale (per evitare di digitare "std ::" non necessari).

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

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

Qual è lo scopo di questa dichiarazione? Se lo faccio in un'intestazione, inietterà queste dichiarazioni di "utilizzo" in ogni file cpp che include l'intestazione?


18
Nel caso in cui non sia chiaro dalle altre risposte qui: - Non inserire una usingdichiarazione (o usingdirettiva) nell'ambito del file in un file / intestazione di inclusione! Ciò causerà mal di testa agli utenti dell'intestazione.
Michael Burr,

In realtà, non mettere una usingdichiarazione (a maggior ragione direttiva ) in un colpo di testa a tutti , anche all'interno di uno spazio dei nomi! Vedere l' ambito di utilizzo della dichiarazione all'interno di uno spazio dei nomi per i problemi che ciò causa.
Nils von Barth

@ NilsvonBarth: Questo è un po 'semplificato. L'uso usingin ambito di classe e funzione è sicuro per quanto riguarda il problema discusso.
Sebastian Mach


Potresti essere interessato a leggere informazioni sulla funzionalità di ricerca di ADL C ++ .
Alexis Wilke il

Risposte:


59

Quando #includi un file di intestazione in C ++, inserisce l'intero contenuto del file di intestazione nel punto in cui lo hai incluso nel file di origine. Quindi includere un file che ha una usingdichiarazione ha lo stesso identico effetto di posizionare la usingdichiarazione all'inizio di ogni file che include quel file di intestazione.


51
... che generalmente è una cosa negativa.
Catskul

17
Ma se metti la usingdichiarazione all'interno di una namespaceè limitata all'ambito di quello spazio dei nomi, quindi è generalmente OK (con i soliti avvertimenti sulle tue esigenze e stile particolari).
Zero

1
... ma se metti using all'interno di uno spazio dei nomi, assicurati di non farlo per cercare di aggirare qualcosa che normalmente è una cattiva idea, come non puoi racchiudere metodi di classe dichiarati al di fuori dello spazio dei nomi Y all'interno dell'altro namespace X, solo così puoi usare localmente lo spazio dei nomi X. Ecco perché abbiamo usato namespace :: resolver in primo luogo. Se è un grosso problema di digitazione, una macro (che può facilmente portare a odori di codice) o meglio ancora, isolala nel suo .cpp sorgente dove utilizzerai lo spazio dei nomi solo lì.
osirisgothra

1
Sebbene questa e altre risposte simili siano buoni consigli, non rispondono alla domanda.
Emile Cormier

116

Non c'è niente di speciale nei file di intestazione che manterrebbero la usingdichiarazione. È una semplice sostituzione del testo prima ancora che inizi la compilazione.

Puoi limitare una usingdichiarazione a un ambito:

void myFunction()
{
   using namespace std; // only applies to the function's scope
   vector<int> myVector;
}

12
Non avrei mai pensato di poterlo utilizzare all'interno di una funzione!
Agostino

1
Ho un sacco di spazi dei nomi tutti usati da un file di tipo "conglomeratore", e il test unitario di gmock era molto noioso perché ogni test utilizzava cose da uno spazio dei nomi specifico, e ho pensato di dover qualificare ogni singola variabile. Usare usingall'interno di una funzione (o anche una TESTmacro gtest !) Rende la mia vita molto migliore!
dwanderson

54

L'ambito dell'istruzione using dipende da dove si trova nel codice:

  • Posizionato all'inizio di un file, ha un ambito in tutto quel file.
  • Se questo è un file di intestazione, avrà ambito in tutti i file che includono quell'intestazione. In generale, questa " non è una buona idea " in quanto può avere effetti collaterali inaspettati
  • Altrimenti l' istruzione using ha ambito all'interno del blocco che la contiene dal punto in cui si verifica alla fine del blocco. Se viene inserito in un metodo, avrà un ambito all'interno di quel metodo. Se viene inserito all'interno di una definizione di classe, avrà un ambito all'interno di quella classe.

5
Pensavo non fosse possibile aggiungere usingun'istruzione nell'ambito della classe ...? Ho avuto la stessa domanda dell'OP per questo motivo perché volevo evitare di digitare ovunque std::. Ho classi che utilizzano molti vettori con puntatori intelligenti e il std::prefisso a cinque caratteri aggiunge molta lunghezza della riga, cosa che trovo peggiore. Quindi mi chiedevo se una usingdirettiva all'interno dello spazio dei nomi contenente la classe fosse ok? (Anche se all'interno di un'intestazione.)
thomthom

5
E se fosse inserito nell'ambito di un namespace { ... }?
einpoklum

Quindi puoi scrivere totalmente: {using namespace blabla; classe blah {}; } e che using si applicherà solo alla classe?
Dinaiz

8

L'ambito è l'ambito in cui si trova la dichiarazione using.

Se questo è un ambito globale, allora sarà un ambito globale. Se è nell'ambito globale di un file di intestazione, sarà nell'ambito di ogni file sorgente che include l'intestazione.

Quindi, il consiglio generale è di evitare di utilizzare le dichiarazioni nell'ambito globale dei file di intestazione .


3
Non è abbastanza forte. Sostituisci evitare con Non
Martin York

1
Ma evitare è più forte di non farlo. "Evita di colpire le altre macchine"
bobobobo

6

Nel caso citato, il file ("unità di traduzione"), che significa sì, ogni file che lo include.

Puoi anche inserire l'istruzione using all'interno della classe, nel qual caso è valida solo per quella classe.

In genere, se è necessario specificare uno spazio dei nomi in un'intestazione, spesso è meglio qualificare completamente ogni identificatore necessario.


Nota che la usingdichiarazione in una classe non si comporta allo stesso modo che all'esterno di una classe, ad esempio non puoi usarla bring coutinvece che std::coutnell'ambito della classe.
Zero

2

È corretto. L'ambito è il modulo che utilizza la usingdichiarazione. Se i file di intestazione inclusi in un modulo hanno usingdichiarazioni, l'ambito di tali dichiarazioni sarà quel modulo, così come qualsiasi altro modulo che includa le stesse intestazioni.


1

Ci sono alcuni commenti che sono piuttosto non qualificati quando dicono "Non". È troppo severo, ma devi capire quando va bene.

Scrivere using std::stringnon è mai OK. Scrivendo using ImplementationDetail::Foonella propria intestazione, quando quell'intestazione dichiara ImplementationDetail :: Foo può essere OK, anche se la dichiarazione using avviene nel proprio spazio dei nomi. Per esempio

namespace MyNS {
    namespace ImplementationDetail {
        int Foo;
    }
    using ImplementationDetail::Foo;
}

1
L'utente dell'intestazione può quindi scrivereMyNS::Foo
Peter Remmers

Un esempio migliore è using boost::posix_time::ptime. Sicuramente l'utente potrebbe scrivere MyNS::ptimema non è la fine del mondo e potrebbe essere compensato dalla comodità di poter avere funzioni come MyFunction(ptime a, ptime b).
Zero

5
Perchéusing std::string non va mai bene? Anche nel tuo spazio dei nomi per salvare molti std::prefissi?
thomthom

@thomthom va bene se racchiuso in uno scope come il tuo spazio dei nomi.
jcoffland
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.