c++ está - ¿Para qué son los espacios de nombres en línea?




el que (3)

Los espacios de nombres en línea son una función de versionamiento de biblioteca similar a la versión de símbolos , pero se implementan únicamente en el nivel de 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 mediante 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 la primera no -en línea del espacio de nombres y mire y actúe como si sus declaraciones estuvieran en cualquiera de los espacios de nombres intermedios también.

Como ejemplo, consideremos la implementación STL de vector . Si tuviéramos espacios de nombres en línea desde el principio de C ++, 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 , se __cplusplus una u otra implementación vector . Si su base de código se escribió antes de C ++ 98 veces, y encuentra que la versión de vector de C ++ 98 le está causando problemas al actualizar su compilador, "todo" lo que tiene que hacer es encontrar las referencias a std::vector en tu base de código y reemplázalos por std::pre_cxx_1997::vector .

Viene el siguiente estándar, y el proveedor de STL simplemente repite el procedimiento nuevamente, introduciendo un nuevo espacio de nombres para std::vector con soporte emplace_back (que requiere C ++ 11) e incorporando uno si __cplusplus == 201103L .

OK, entonces ¿por qué necesito una nueva característica 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 de C ++ 98 válido (ya se le permitió especializar completamente las plantillas que viven en el espacio de nombres estándar 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 donde 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) la STL.

Pero : cuando se especializa una plantilla, debe hacerlo en el espacio de nombres en el que se declaró. El Estándar dice que el vector se declara en el espacio de nombres estándar, de modo que ahí es donde el usuario espera legítimamente especializar el tipo.

Este código funciona con un espacio de nombres sin versión estándar o con la función de espacio de nombres en línea de C ++ 11, pero no con el truco de control de versiones que utiliza el using namespace <nested> , ya que expone el detalle de implementación que el verdadero espacio de nombres en el cual vector estaba Definido no era std directamente.

Hay otros orificios por los que 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 (aunque me encantaría demostrar que está equivocado), por lo que solo se puede utilizar para bibliotecas de terceros, no el estándar en sí (a menos que los proveedores del compilador acuerden un esquema de nombres).

C ++ 11 permite inline namespace , todos los miembros de los cuales también se encuentran automáticamente en el namespace adjunto. No puedo pensar en ninguna aplicación útil de esto. ¿Alguien puede dar un ejemplo breve y conciso de una situación donde se necesita un inline namespace y donde es la solución más idiomática?

(Además, no me queda claro qué sucede cuando un namespace se declara en inline en una, pero no en todas las declaraciones, que pueden estar en archivos diferentes. ¿No es esto un problema?)


http://www.stroustrup.com/C++11FAQ.html#inline-namespace (un documento escrito y mantenido por Bjarne Stroustrup, que usted pensaría que debería conocer la mayoría de las motivaciones para la mayoría de las funciones de C ++ 11. )

De acuerdo con eso, es para permitir la creación de versiones para la compatibilidad con versiones anteriores. Usted define múltiples espacios de nombres internos, y hace que el más reciente esté en inline . O de todos modos, el predeterminado para las personas que no se preocupan por las versiones. Supongo que la más reciente podría ser una versión futura o de vanguardia que aún no está predeterminada.

El ejemplo dado es:

// file V99.h:
inline namespace V99 {
    void f(int);    // does something better than the V98 version
    void f(double); // new feature
    // ...
}

// file V98.h:
namespace V98 {
    void f(int);    // does something
    // ...
}

// file Mine.h:
namespace Mine {
#include "V99.h"
#include "V98.h"
}

#include "Mine.h"
using namespace Mine;
// ...
V98::f(1);  // old version
V99::f(1);  // new version
f(1);       // default version

No entiendo de inmediato por qué no using namespace V99; dentro de namespace Mine , pero no tengo que entender completamente el caso de uso para tomar la palabra de Bjarne sobre la motivación del comité.


-- es el operador de disminución y > es el operador mayor que .

Los dos operadores se aplican como uno solo como --> .





c++ namespaces c++11 inline-namespaces