Les espaces de noms en ligne sont une fonctionnalité de versionnage de bibliothèque semblable à la version de symboles , mais implémentée uniquement au niveau C ++ 11 (c'est-à-dire multiplateforme) au lieu d'être une fonctionnalité d'un format exécutable binaire spécifique (c'est-à-dire spécifique à la plate-forme).
C'est un mécanisme par lequel un auteur de bibliothèque peut faire ressembler un espace de noms imbriqué et agir comme si toutes ses déclarations se trouvaient dans l'espace de noms environnant (les espaces de noms en ligne peuvent être imbriqués, donc les noms "plus imbriqués" s'infiltrent jusqu'au premier non -inline namespace et regardez et agissez comme si leurs déclarations se trouvaient également dans l'un des espaces de noms).
Par exemple, considérons l'implémentation STL de vector
. Si nous avions des espaces de noms en ligne depuis le début de C ++, alors en C ++ 98 l'en-tête <vector>
aurait pu ressembler à ceci:
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
En fonction de la valeur de __cplusplus
, l'une ou l'autre vector
implémentation est choisie. Si votre base de code a été écrite en pré-C ++ 98 fois et que vous constatez que la version C ++ 98 vector
vous pose problème lorsque vous mettez à niveau votre compilateur, "tout" vous devez faire est de trouver les références à std::vector
dans votre base de code et remplacez-les par std::pre_cxx_1997::vector
.
Venez la prochaine norme, et le fournisseur STL répète simplement la procédure à nouveau, en introduisant un nouvel espace de noms pour std::vector
avec emplace_back
support (qui nécessite C ++ 11) et en l'incluant __cplusplus == 201103L
.
OK, alors pourquoi ai-je besoin d'une nouvelle fonctionnalité de langue pour cela? Je peux déjà faire ce qui suit pour avoir le même effet, non?
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
En fonction de la valeur de __cplusplus
, j'obtiens l'une ou l'autre des implémentations.
Et vous auriez presque raison.
Considérez le code utilisateur C ++ 98 valide suivant (il était autorisé de spécialiser complètement les modèles qui vivent déjà dans l'espace std
de noms en 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
C'est un code parfaitement valide où l'utilisateur fournit sa propre implémentation d'un vecteur pour un ensemble de type où il connaît apparemment une implémentation plus efficace que celle trouvée dans (sa copie de) la STL.
Mais : lors de la spécialisation d'un modèle, vous devez le faire dans l'espace de noms dans lequel il a été déclaré. Le standard indique qu'il vector
est déclaré dans l'espace de noms std
, c'est donc là que l'utilisateur s'attend à juste titre à spécialiser le type.
Ce code fonctionne avec un espace de noms non versionné std
, ou avec la fonctionnalité d'espace de noms en ligne C ++ 11, mais pas avec l'astuce de versioning utilisée using namespace <nested>
, car cela expose les détails d'implémentation que le véritable espace de noms dans lequel a vector
été défini n'était pas std
directement.
Il existe d'autres trous par lesquels vous pouvez détecter l'espace de noms imbriqué (voir les commentaires ci-dessous), mais les espaces de noms en ligne les bouchent tous. Et c'est tout ce qu'il y a à faire. Immensément utile pour l'avenir, mais AFAIK the Standard ne prescrit pas de noms d'espace de noms en ligne pour sa propre bibliothèque standard (j'aimerais bien me tromper à ce sujet), donc il ne peut être utilisé que pour des bibliothèques tierces, pas la norme elle-même (à moins que les fournisseurs du compilateur ne conviennent d'un schéma de dénomination).
using namespace V99;
ne fonctionne pas dans l'exemple de Stroustrup.