Inline-Namespaces sind eine Bibliotheksversionierungsfunktion, die der Symbolversionierung ähnelt , jedoch nur auf C ++ 11-Ebene (dh plattformübergreifend) implementiert wird, anstatt eine Funktion eines bestimmten ausführbaren Binärformats (dh plattformspezifisch) zu sein.
Es ist ein Mechanismus, mit dem ein Bibliotheksautor einen verschachtelten Namespace so aussehen lassen kann, als ob alle seine Deklarationen im umgebenden Namespace wären (Inline-Namespaces können verschachtelt werden, sodass "mehr verschachtelte" Namen bis zum ersten Nicht-Namespace versickern -inline-Namespace und sehen aus und tun so, als ob ihre Deklarationen auch in einem der dazwischen liegenden Namespaces wären).
Betrachten Sie als Beispiel die STL-Implementierung von vector. Wenn wir seit Beginn von C ++ Inline-Namespaces <vector>hätten, hätte der Header in C ++ 98 möglicherweise so ausgesehen:
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
Abhängig vom Wert von __cpluspluswird entweder die eine oder die andere vectorImplementierung ausgewählt. Wenn Ihre Codebasis 98-mal vor C ++ geschrieben wurde und Sie feststellen, dass die C ++ 98-Version von vectorIhnen beim Upgrade Ihres Compilers Probleme bereitet, müssen Sie nur die Verweise auf std::vectorin finden Ihre Codebasis und ersetzen Sie sie durch std::pre_cxx_1997::vector.
Kommen Sie zum nächsten Standard, und der STL-Anbieter wiederholt den Vorgang einfach erneut, indem er einen neuen Namespace std::vectormit emplace_backUnterstützung (für den C ++ 11 erforderlich ist) einführt und diesen iff einfügt __cplusplus == 201103L.
OK, warum brauche ich dafür eine neue Sprachfunktion? Ich kann schon folgendes tun, um den gleichen Effekt zu erzielen, nein?
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
Je nach Wert von __cplusplusbekomme ich entweder die eine oder die andere Implementierung.
Und du wärst fast richtig.
Betrachten Sie den folgenden gültigen C ++ 98-Benutzercode (es war zulässig, Vorlagen, die sich bereits stdin C ++ 98 im Namespace befinden, vollständig zu spezialisieren ):
// 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
Dies ist ein vollkommen gültiger Code, bei dem der Benutzer seine eigene Implementierung eines Vektors für eine Reihe von Typen bereitstellt, bei denen er anscheinend eine effizientere Implementierung kennt als die, die in (ihrer Kopie) der STL zu finden ist.
Aber : Wenn Sie eine Vorlage spezialisieren, müssen Sie dies in dem Namespace tun, in dem sie deklariert wurde. Der Standard sagt, dass dies vectorim Namespace deklariert ist std, sodass der Benutzer zu Recht erwartet, den Typ zu spezialisieren.
Dieser Code funktioniert mit einem nicht versionierten Namespace stdoder mit der C ++ 11-Inline-Namespace-Funktion, jedoch nicht mit dem verwendeten Versionierungstrick using namespace <nested>, da dadurch das Implementierungsdetail angezeigt wird, dass der wahre Namespace, in dem vectordefiniert wurde, nicht stddirekt war.
Es gibt andere Lücken, anhand derer Sie den verschachtelten Namespace erkennen können (siehe Kommentare unten), aber Inline-Namespaces schließen sie alle. Und das ist alles. Immens nützlich für die Zukunft, aber AFAIK the Standard schreibt keine Inline-Namespace-Namen für seine eigene Standardbibliothek vor (ich würde mich jedoch gerne als falsch erweisen), sodass es nur für Bibliotheken von Drittanbietern verwendet werden kann, nicht der Standard selbst (es sei denn, die Compiler-Anbieter einigen sich auf ein Namensschema).
using namespace V99;in Stroustrups Beispiel nicht funktioniert.