Jaki jest zakres deklaracji „using” w C ++?

100

Używam deklaracji „using” w C ++, aby dodać std :: string i std :: vector do lokalnej przestrzeni nazw (aby zaoszczędzić wpisywanie niepotrzebnych „std ::”).

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

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

Jaki jest zakres tej deklaracji? Jeśli zrobię to w nagłówku, czy wstrzyknie te deklaracje „using” do każdego pliku cpp, który zawiera nagłówek?

Jeff Lake
źródło
18
Na wypadek, gdyby nie było to jasne z innych odpowiedzi tutaj: - Nie umieszczaj usingdeklaracji (lub usingdyrektywy) w zakresie pliku w dołączonym pliku / nagłówku! To spowoduje ból głowy u użytkowników nagłówka.
Michael Burr
W rzeczywistości, nie umieścić usingdeklarację (a fortiori dyrektywa ) w nagłówku w ogóle , nawet w obrębie przestrzeni nazw! Zobacz zakres używania deklaracji w przestrzeni nazw dla problemów, które powoduje.
Nils von Barth
@NilsvonBarth: To trochę zbytnio uproszczone. Zastosowanie usingw zakresie klas i funkcji jest bezpieczne w omawianym problemie.
Sebastian Mach,
Możesz być zainteresowany poczytaniem o funkcji wyszukiwania ADL C ++ .
Alexis Wilke,

Odpowiedzi:

59

Kiedy # dołączasz plik nagłówkowy w C ++, umieszcza on całą zawartość pliku nagłówkowego w miejscu, w którym umieściłeś go w pliku źródłowym. Zatem dołączenie pliku, który ma usingdeklarację, ma dokładnie taki sam efekt, jak umieszczenie usingdeklaracji na początku każdego pliku, który zawiera ten plik nagłówkowy.

Jeremy Ruten
źródło
51
... co jest ogólnie złą rzeczą.
Catskul,
17
Ale jeśli umieścisz usingdeklarację wewnątrz a namespace, jest ona ograniczona do zakresu tej przestrzeni nazw, więc ogólnie jest OK (ze zwykłymi zastrzeżeniami dotyczącymi twoich konkretnych potrzeb i stylu).
Zero
1
... ale jeśli umieścisz użycie wewnątrz przestrzeni nazw, upewnij się, że nie robisz tego, aby spróbować obejść coś, co normalnie jest złym pomysłem, na przykład nie możesz zamknąć metod klas zadeklarowanych poza przestrzenią nazw Y wewnątrz innej namespace X, tylko po to, abyś mógł lokalnie używać przestrzeni nazw X. Właśnie dlatego użyliśmy przede wszystkim namespace :: resolvers. Jeśli jest to tak duży problem z pisaniem, albo makra (które może łatwo prowadzić do zapachów kodu), albo jeszcze lepiej, izoluj je do własnego źródła .cpp, w którym będziesz używać tylko tam przestrzeni nazw.
osirisgothra
1
Chociaż ta i podobne odpowiedzi są dobrą radą, nie odpowiadają na pytanie.
Emile Cormier
116

Nie ma nic specjalnego w plikach nagłówkowych, które powstrzymywałyby usingdeklarację przed ujawnieniem. Jest to proste podstawianie tekstu przed rozpoczęciem kompilacji.

Możesz ograniczyć usingdeklarację do zakresu:

void myFunction()
{
   using namespace std; // only applies to the function's scope
   vector<int> myVector;
}
Zaćmienie
źródło
12
Nigdy nie myślałem, że mogę go użyć w funkcji!
Agostino
1
Mam kilka przestrzeni nazw, z których wszystkie są używane przez jeden plik typu „konglomerator”, a testy jednostkowe gmocka były wyjątkowo żmudne, ponieważ każdy test używał rzeczy z określonej przestrzeni nazw i pomyślałem, że muszę zakwalifikować każdą zmienną. Używanie usingwewnątrz funkcji (lub nawet TESTmakra gtest !) Sprawia, że ​​moje życie jest o wiele lepsze!
dwanderson
54

Zakres instrukcji using zależy od tego, gdzie się ona znajduje w kodzie:

  • Umieszczony na początku pliku, ma zasięg w całym pliku.
  • Jeśli jest to plik nagłówkowy, będzie miał zasięg we wszystkich plikach, które zawierają ten nagłówek. Ogólnie jest to „ zły pomysł ”, ponieważ może mieć nieoczekiwane skutki uboczne
  • W przeciwnym razie instrukcja using ma zasięg w obrębie bloku, który ją zawiera, od punktu, w którym występuje, do końca bloku. Jeśli zostanie umieszczony w metodzie, będzie miał zasięg w ramach tej metody. Jeśli zostanie umieszczony w definicji klasy, będzie miał zasięg w tej klasie.
dagorym
źródło
5
Myślałem, że nie można dodać usinginstrukcji w zakresie klasy ...? Miałem to samo pytanie, co OP, ponieważ chciałem uniknąć pisania w std::każdym miejscu. Mam klasy, które używają wielu wektorów z inteligentnymi wskaźnikami, a pięcioznakowy std::prefiks dodaje dużo długości linii - co wydaje mi się gorsze. Więc zastanawiałem się, czy usingdyrektywa w przestrzeni nazw zawierającej klasę jest w porządku? (Nawet jeśli w nagłówku.)
thomthom
5
A co, jeśli zostanie umieszczony w zakresie namespace { ... }?
einpoklum
Możesz więc całkowicie napisać: {using namespace blabla; class blah {}; } i że użycie będzie dotyczyło tylko klasy?
Dinaiz
8

Zakres jest dowolnym zakresem, w którym znajduje się deklaracja using.

Jeśli jest to zasięg globalny, będzie to zasięg globalny. Jeśli jest w zasięgu globalnym pliku nagłówkowego, będzie w zasięgu globalnym każdego pliku źródłowego, który zawiera nagłówek.

Dlatego ogólną radą jest unikanie używania deklaracji w globalnym zakresie plików nagłówkowych .

JohnMcG
źródło
3
To nie jest wystarczająco mocne. Zamień unikaj na Nie
Martin York
1
Jednak unikanie jest silniejsze niż nie. „Unikaj
zderzenia
6

W przytoczonym przypadku plik („jednostka tłumaczeniowa”), co oznacza tak, każdy plik, który go zawiera.

Możesz również umieścić instrukcję using wewnątrz klasy, w takim przypadku obowiązuje ona tylko dla tej klasy.

Ogólnie rzecz biorąc, jeśli musisz określić przestrzeń nazw w nagłówku, często najlepiej jest po prostu w pełni zakwalifikować każdy wymagany identyfikator.

James Curran
źródło
Zwróć uwagę, że usingdeklaracja w klasie nie zachowuje się tak samo, jak poza klasą - np. Nie możesz jej użyć bring coutzamiast std::coutdo zakresu klasy.
Zero
2

To jest poprawne. Zakres to moduł używający usingdeklaracji. Jeśli jakiekolwiek pliki nagłówkowe, które zawiera moduł, mają usingdeklaracje, zakresem tych deklaracji będzie ten moduł, a także wszelkie inne moduły, które zawierają te same nagłówki.

Ates Goral
źródło
1

Jest kilka komentarzy, które są raczej bez zastrzeżeń, kiedy mówią „Nie”. To zbyt surowe, ale musisz zrozumieć, kiedy jest OK.

Pisanie using std::stringnigdy nie jest w porządku. Pisanie using ImplementationDetail::Foowe własnym nagłówku, gdy ten nagłówek deklaruje ImplementationDetail :: Foo może być OK, więcej, jeśli deklaracja using ma miejsce w Twojej przestrzeni nazw. Na przykład

namespace MyNS {
    namespace ImplementationDetail {
        int Foo;
    }
    using ImplementationDetail::Foo;
}
MSalters
źródło
1
Użytkownik nagłówka może wtedy pisaćMyNS::Foo
Peter Remmers
Lepszym przykładem jest using boost::posix_time::ptime. Jasne, że użytkownik mógłby pisać, MyNS::ptimeale to nie koniec świata i może to być zrekompensowane wygodą posiadania funkcji takich jak MyFunction(ptime a, ptime b).
Zero
5
Dlaczegousing std::string nigdy nie jest w porządku? Nawet we własnej przestrzeni nazw, aby zapisać wiele std::prefiksów?
thomthom
@thomthom jest ok, gdy jest opakowany w zakres, taki jak twoja własna przestrzeń nazw.
jcoffland