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 __cplusplus
wird entweder die eine oder die andere vector
Implementierung ausgewählt. Wenn Ihre Codebasis 98-mal vor C ++ geschrieben wurde und Sie feststellen, dass die C ++ 98-Version von vector
Ihnen beim Upgrade Ihres Compilers Probleme bereitet, müssen Sie nur die Verweise auf std::vector
in 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::vector
mit emplace_back
Unterstü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 __cplusplus
bekomme 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 std
in 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 vector
im Namespace deklariert ist std
, sodass der Benutzer zu Recht erwartet, den Typ zu spezialisieren.
Dieser Code funktioniert mit einem nicht versionierten Namespace std
oder 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 vector
definiert wurde, nicht std
direkt 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.