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 __cplusplusjedna lub druga vectorimplementacja. Jeśli codebase został napisany w pre-C ++ 98 razy, a okaże się, że C ++ 98 wersja vectorjest przyczyną kłopotów dla ciebie, kiedy uaktualnić kompilator, „wszystkie”, co musisz zrobić, to znaleźć odniesienia do std::vectorw 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::vectorz emplace_backobsł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 __cplusplusotrzymuję 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 stdw 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 vectorjest 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 stdlub 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 vectorzostała zdefiniowana, nie była stdbezpoś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.