Najpierw trochę terminologii:
- deklaracja użycia :
using std::vector;
- using-dyrektywa :
using namespace std;
Myślę, że używanie dyrektyw using jest w porządku, o ile nie są one używane w globalnym zakresie w pliku nagłówkowym. Więc mając
using namespace std;
w twoim pliku .cpp nie jest tak naprawdę problemem, a jeśli okaże się, że tak jest, jest całkowicie pod twoją kontrolą (i można go nawet przypisać do konkretnych bloków, jeśli chcesz). Nie widzę żadnego szczególnego powodu, aby zaśmiecać kod std::
mnóstwem kwalifikatorów - staje się to po prostu kupą wizualnego szumu. Jeśli jednak std
w swoim kodzie nie używasz całej grupy nazw z przestrzeni nazw, nie widzę problemu z pominięciem dyrektywy. To tautologia - jeśli dyrektywa nie jest konieczna, nie ma potrzeby jej używać.
Podobnie, jeśli możesz sobie poradzić z kilkoma deklaracjami using (zamiast using-directives ) dla określonych typów w std
przestrzeni nazw, to nie ma powodu, dla którego nie powinieneś mieć tylko tych spefcific nazw przenoszonych do bieżącej przestrzeni nazw. Z tego samego powodu myślę, że byłoby szalone i kłopotliwe z księgowością mieć 25 lub 30 deklaracji using, podczas gdy pojedyncza dyrektywa using równie dobrze wystarczyłaby.
Warto również pamiętać, że czasami trzeba użyć deklaracji using. Zapoznaj się z „Punkt 25: Rozważ obsługę wymiany bez rzucania” Scotta Meyersa z Effective C ++, wydanie trzecie. Aby ogólna funkcja oparta na szablonie używała `` najlepszej '' metody zamiany dla typu sparametryzowanego, musisz użyć deklaracji użycia i wyszukiwania zależnego od argumentów (aka ADL lub Koenig lookup):
template< typename T >
void foo( T& x, T& y)
{
using std::swap; // makes std::swap available in this function
// do stuff...
swap( x, y); // will use a T-specific swap() if it exists,
// otherwise will use std::swap<T>()
// ...
}
Myślę, że powinniśmy przyjrzeć się popularnym idiomom dla różnych języków, które w znacznym stopniu wykorzystują przestrzenie nazw. Na przykład Java i C # używają w dużym stopniu przestrzeni nazw (prawdopodobnie bardziej niż C ++). Najpopularniejszym sposobem używania nazw w przestrzeniach nazw w tych językach jest masowe przenoszenie ich do obecnego zakresu za pomocą odpowiednika dyrektywy using. Nie powoduje to powszechnych problemów, a kilka przypadków jest obsługiwanych na zasadzie „wyjątków”, zajmując się nazwami, o których mowa, za pomocą w pełni kwalifikowanych nazw lub aliasów - tak jak można to zrobić w C ++.
Herb Sutter i Andrei Alexandrescu mają to do powiedzenia w „Punkcie 59: Nie zapisuj użycia przestrzeni nazw w pliku nagłówkowym lub przed #include” w swojej książce C ++ Coding Standards: 101 Rules, Guidelines, and Best Practices:
W skrócie: możesz i powinieneś używać przestrzeni nazw, swobodnie używając deklaracji i dyrektyw w swoich plikach implementacji po #include
dyrektywach i dobrze się z tym czujesz. Pomimo wielokrotnych twierdzeń, że jest inaczej, przestrzenie nazw używające deklaracji i dyrektyw nie są złe i nie są sprzeczne z celem przestrzeni nazw. To raczej one sprawiają, że przestrzenie nazw są użyteczne.
Stroupstrup jest często cytowany jako powiedzenie „Nie zanieczyszczaj globalnej przestrzeni nazw” w „Języku programowania C ++, wydanie trzecie”. Faktycznie mówi to (C.14 [15]), ale odsyła do rozdziału C.10.1, w którym mówi:
Użyciu deklaracja dodaje nazwę do zakresu lokalnego. Użyciu Dyrektywa nie robi; po prostu udostępnia nazwy w zakresie, w którym zostały zadeklarowane. Na przykład:
namespaceX {
int i , j , k ;
}
int k ;
void f1()
{
int i = 0 ;
using namespaceX ; // make names from X accessible
i++; // local i
j++; // X::j
k++; // error: X::k or global k ?
::k ++; // the global k
X::k ++; // X’s k
}
void f2()
{
int i = 0 ;
using X::i ; // error: i declared twice in f2()
using X::j ;
using X::k ; // hides global k
i++;
j++; // X::j
k++; // X::k
}
Nazwa zadeklarowana lokalnie (zadeklarowana przez zwykłą deklarację lub przez deklarację using) ukrywa nielokalne deklaracje o tej samej nazwie, a wszelkie niedozwolone przeciążenia nazwy są wykrywane w miejscu deklaracji.
Zwróć uwagę na błąd niejednoznaczności k++
w
f1()
. Nazwy globalne nie mają pierwszeństwa przed nazwami z przestrzeni nazw udostępnionych w zasięgu globalnym. Zapewnia to znaczną ochronę przed przypadkowymi konfliktami nazw i - co ważne - zapewnia, że zanieczyszczenie globalnej przestrzeni nazw nie przynosi żadnych korzyści.
Gdy biblioteki deklarujące wiele nazw są udostępniane za pomocą dyrektyw using, istotną zaletą jest to, że kolizje nieużywanych nazw nie są uważane za błędy.
...
Mam nadzieję, że w porównaniu z tradycyjnymi programami w językach C i C ++, w nowych programach korzystających z przestrzeni nazw nastąpi radykalny spadek użycia nazw globalnych. Reguły dla przestrzeni nazw zostały specjalnie opracowane, aby nie dawać „leniwemu” użytkownikowi nazw globalnych żadnej przewagi nad kimś, kto dba o to, aby nie zanieczyszczać zasięgu globalnego.
A jak można mieć tę samą przewagę jako „leniwy użytkownik globalnych nazw”? Korzystając z dyrektywy using, która bezpiecznie udostępnia nazwy w przestrzeni nazw dla bieżącego zakresu.
Zauważ, że istnieje różnica - nazwy w std
przestrzeni nazw udostępniane zakresowi z odpowiednim użyciem dyrektywy using (umieszczając dyrektywę po niej #includes
) nie zanieczyszczają globalnej przestrzeni nazw. Po prostu ułatwia dostęp do tych nazw i zapewnia ciągłą ochronę przed kolizjami.