Wewnętrzne przestrzenie nazw są funkcją wersjonowania biblioteki podobną do wersji symboli , ale zaimplementowaną wyłącznie na poziomie C ++ 11 (tj. Międzyplatformowym) zamiast być cechą określonego binarnego formatu wykonywalnego (tj. Specyficznego dla platformy).
Jest to mechanizm, dzięki któremu autor biblioteki może sprawić, aby zagnieżdżona przestrzeń nazw wyglądała i działała tak, jakby wszystkie jej deklaracje znajdowały się w otaczającej przestrzeni nazw (wbudowane przestrzenie nazw można zagnieżdżać, dzięki czemu nazwy „bardziej zagnieżdżone” przenikają aż do pierwszego -inline przestrzeń nazw i wygląda i działa tak, jakby ich deklaracje znajdowały się również w jednej z przestrzeni nazw pomiędzy nimi).
Jako przykład rozważ implementację STL vector
. Gdybyśmy mieli wbudowane przestrzenie nazw od początku C ++, to w C ++ 98 nagłówek <vector>
mógłby wyglądać tak:
namespace std {
#if __cplusplus < 1997L // pre-standard C++
inline
#endif
namespace pre_cxx_1997 {
template <class T> __vector_impl; // implementation class
template <class T> // e.g. w/o allocator argument
class vector : __vector_impl<T> { // private inheritance
// ...
};
}
#if __cplusplus >= 1997L // C++98/03 or later
// (ifdef'ed out b/c it probably uses new language
// features that a pre-C++98 compiler would choke on)
# if __cplusplus == 1997L // C++98/03
inline
# endif
namespace cxx_1997 {
// std::vector now has an allocator argument
template <class T, class Alloc=std::allocator<T> >
class vector : pre_cxx_1997::__vector_impl<T> { // the old impl is still good
// ...
};
// and vector<bool> is special:
template <class Alloc=std::allocator<bool> >
class vector<bool> {
// ...
};
};
#endif // C++98/03 or later
} // namespace std
W zależności od wartości wybierana jest __cplusplus
jedna lub druga vector
implementacja. Jeśli codebase został napisany w pre-C ++ 98 razy, a okaże się, że C ++ 98 wersja vector
jest przyczyną kłopotów dla ciebie, kiedy uaktualnić kompilator, „wszystkie”, co musisz zrobić, to znaleźć odniesienia do std::vector
w twoją bazę kodów i zastąp je std::pre_cxx_1997::vector
.
Przyjdź następny standard, a sprzedawca STL po prostu ponownie powtarza procedurę, wprowadzając nową przestrzeń nazw std::vector
z emplace_back
obsługą (która wymaga C ++ 11) i wstawiając tę iff __cplusplus == 201103L
.
OK, więc dlaczego potrzebuję do tego nowej funkcji językowej? Mogę już wykonać następujące czynności, aby uzyskać ten sam efekt, nie?
namespace std {
namespace pre_cxx_1997 {
// ...
}
#if __cplusplus < 1997L // pre-standard C++
using namespace pre_cxx_1997;
#endif
#if __cplusplus >= 1997L // C++98/03 or later
// (ifdef'ed out b/c it probably uses new language
// features that a pre-C++98 compiler would choke on)
namespace cxx_1997 {
// ...
};
# if __cplusplus == 1997L // C++98/03
using namespace cxx_1997;
# endif
#endif // C++98/03 or later
} // namespace std
W zależności od wartości __cplusplus
otrzymuję jedną z tych implementacji.
I miałbyś prawie rację.
Rozważ następujący poprawny kod użytkownika C ++ 98 (dozwolone było w pełni specjalizowanie szablonów, które już istnieją w przestrzeni nazw std
w C ++ 98):
// I don't trust my STL vendor to do this optimisation, so force these
// specializations myself:
namespace std {
template <>
class vector<MyType> : my_special_vector<MyType> {
// ...
};
template <>
class vector<MyOtherType> : my_special_vector<MyOtherType> {
// ...
};
// ...etc...
} // namespace std
Jest to całkowicie poprawny kod, w którym użytkownik dostarcza własną implementację wektora dla zestawu typów, w którym najwyraźniej zna bardziej wydajną implementację niż ta znaleziona w (jej kopii) STL.
Ale : Specjalizując się w szablonie, musisz to zrobić w przestrzeni nazw, w której został zadeklarowany. Standard mówi, że vector
jest zadeklarowany w przestrzeni nazw std
, więc to właśnie tam użytkownik słusznie spodziewa się specjalizacji typu.
Ten kod działa z niewersjonowaną przestrzenią nazw std
lub z wbudowaną funkcją przestrzeni nazw C ++ 11, ale nie z zastosowaną sztuczką wersjonowania using namespace <nested>
, ponieważ ujawnia szczegół implementacji, że prawdziwa przestrzeń nazw, w której vector
została zdefiniowana, nie była std
bezpośrednio.
Istnieją inne dziury, przez które można wykryć zagnieżdżoną przestrzeń nazw (patrz komentarze poniżej), ale wbudowane przestrzenie nazw zatapiają je wszystkie. I to wszystko. Niezwykle przydatne w przyszłości, ale AFAIK Standard nie określa wbudowanych nazw przestrzeni nazw dla swojej własnej biblioteki standardowej (choć chciałbym, żeby mi się to nie udało), więc można jej używać tylko do bibliotek stron trzecich, a nie sam standard (chyba że dostawcy kompilatora uzgodnią schemat nazewnictwa).
using namespace V99;
nie działa w przykładzie Stroustrupa.