Los espacios de nombres en línea son una característica de versiones de la biblioteca similar a las versiones de símbolos , pero se implementan exclusivamente en el nivel C ++ 11 (es decir, multiplataforma) en lugar de ser una característica de un formato ejecutable binario específico (es decir, específico de la plataforma).
Es un mecanismo por el cual el autor de una biblioteca puede hacer que un espacio de nombres anidado se vea y actúe como si todas sus declaraciones estuvieran en el espacio de nombres circundante (los espacios de nombres en línea se pueden anidar, por lo que los nombres "más anidados" se filtran hasta el primer no -inline espacio de nombres y se ven y actúan como si sus declaraciones estuvieran en cualquiera de los espacios de nombres intermedios, también).
Como ejemplo, considere la implementación de STL de vector
. Si tuviéramos espacios de nombres en línea desde el comienzo de C ++, entonces en C ++ 98 el encabezado <vector>
podría tener este aspecto:
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
Dependiendo del valor de __cplusplus
, vector
se elige una u otra implementación. Si su código base fue escrito en versiones anteriores a C ++ 98 veces, y encuentra que la versión de C ++ 98 le vector
está causando problemas cuando actualiza su compilador, "todo" que tiene que hacer es encontrar las referencias std::vector
en su base de código y reemplácelos por std::pre_cxx_1997::vector
.
Llegue al siguiente estándar, y el proveedor de STL simplemente repite el procedimiento nuevamente, presentando un nuevo espacio de nombres std::vector
con emplace_back
soporte (que requiere C ++ 11) e integrando ese iff __cplusplus == 201103L
.
Bien, entonces ¿por qué necesito una nueva función de idioma para esto? Ya puedo hacer lo siguiente para tener el mismo efecto, ¿no?
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
Dependiendo del valor de __cplusplus
, obtengo una u otra de las implementaciones.
Y estarías casi en lo correcto.
Considere el siguiente código de usuario válido de C ++ 98 (ya estaba permitido especializar completamente las plantillas que viven en el espacio std
de nombres 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
Este es un código perfectamente válido en el que el usuario proporciona su propia implementación de un vector para un conjunto de tipos en el que aparentemente conoce una implementación más eficiente que la que se encuentra en (su copia de) el STL.
Pero : cuando se especializa una plantilla, debe hacerlo en el espacio de nombres en el que se declaró. El Estándar dice que vector
se declara en el espacio de nombres std
, por lo que es allí donde el usuario espera especializar el tipo.
Este código funciona con un espacio de nombres no versionado std
, o con la función de espacio de nombres en línea C ++ 11, pero no con el truco de versiones utilizado using namespace <nested>
, porque eso expone el detalle de implementación de que el verdadero espacio de nombres en el que vector
se definió no estaba std
directamente.
Hay otros agujeros por los cuales puede detectar el espacio de nombres anidado (vea los comentarios a continuación), pero los espacios de nombres en línea los conectan a todos. Y eso es todo lo que hay que hacer. Inmensamente útil para el futuro, pero AFAIK the Standard no prescribe nombres de espacios de nombres en línea para su propia biblioteca estándar (sin embargo, me encantaría que se demuestre lo contrario), por lo que solo se puede usar para bibliotecas de terceros, no el estándar en sí (a menos que los proveedores del compilador acuerden un esquema de nombres).
using namespace V99;
no funciona en el ejemplo de Stroustrup.