scope del uso de la statement dentro de un espacio de nombres

¿Es seguro (y correcto) en un archivo de encabezado C ++ usar la statement using dentro de un espacio de nombres de la siguiente manera:

#include  namespace MyNamespace { using boost::numeric::ublas::vector; vector MyFunc(vector in); } 

Es decir, ¿está usando “boost :: numeric :: ublas :: vector” adecuadamente dentro del bloque MyNamespace, o esto contaminará el espacio de nombres de cualquier archivo que incluya este encabezado?

No, no es seguro; no contaminará otro espacio de nombres, pero es peligroso por otros motivos:

Una directiva de using importará todo lo que esté actualmente visible por el nombre que especifique en el espacio de nombres donde lo usa. Si bien su using solo será visible para los usuarios de MyNamespace , otras cosas desde “afuera” serán visibles para su statement de using .

Entonces, ¿cómo es esto peligroso cuando se usa en un encabezado? Como importará elementos que son visibles en el momento de la statement, el comportamiento exacto dependerá del orden de los encabezados que incluya antes de la statement (Puede haber diferentes elementos visibles de boost::numeric::ublas::vector ). Dado que no se puede controlar realmente qué encabezados se incluyen antes de su encabezado (¡ni debería ser! Los encabezados deberían ser autosuficientes), esto puede conducir a problemas muy extraños donde su función encontrará una cosa en una unidad de comstackción, y otra en el siguiente.

Como regla general, el using declaraciones solo debe utilizarse después de que todas las incluyen en un archivo .cpp. También hay un artículo sobre este tema en el libro “C ++ Coding Standards” de Sutter and Alexandrescu (artículo 59). Aquí hay una cita: “Pero aquí está la trampa común: muchas personas piensan que usar declaraciones emitidas a nivel de espacio de nombres (…) es seguro. No lo son. Son al menos tan peligrosas, y de una manera más sutil e insidiosa”.

Incluso cuando es poco probable que el nombre que está using no exista en ningún otro lugar (como probablemente sea el caso aquí), las cosas pueden ponerse feas: en un encabezado, todas las declaraciones deben calificarse por completo . Esto es dolor, pero de lo contrario, pueden suceder cosas extrañas.

Consulte también Migración a espacios de nombres , declaraciones de uso y alias de nombres de espacios y nombres de nombres para ejemplos y el problema descrito en profundidad.

Una statement de uso es, como su nombre lo dice, una statement. Todas las declaraciones tienen un scope en el bloque adjunto (7.2), en este caso el espacio de nombres MyNamespace . No será visible fuera de ese espacio de nombres.

Es seguro, pero contaminará el espacio de nombres MyNamespace. Por lo tanto, cualquier archivo que incluya ese encabezado tendrá funciones / clases en MyNamespace.

No contaminará ningún otro espacio de nombres, pero ciertamente contaminará el espacio de nombres MyNamespace.

Para resumir, no , usar-declaraciones en un encabezado no está bien , incluso dentro de un espacio de nombres, por 2 razones. Además, el uso de declaraciones dentro de un espacio de nombres en un no-encabezado son propensas a errores o inútiles (véase el final). Las declaraciones de uso en un encabezado no son correctas porque:

  1. Introducen un nombre en el espacio de nombres, que afecta a todos los archivos que incluyen el encabezado.
  2. Introducen solo declaraciones para el nombre que ya se han visto, lo que significa que el comportamiento depende del orden de includes.

En tu ejemplo, esto significa que:

  1. Dentro de MyNamespace , el vector ahora puede resolver para boost::numeric::ublas::vector , para cualquier archivo que incluya este encabezado: “contamina” el espacio de nombres MyNamespace .
  2. Qué boost::numeric::ublas::vector declaraciones boost::numeric::ublas::vector se importan depende de qué declaraciones aparecen antes de esta statement de uso, que depende del orden de las inclusiones en el archivo que incluye este encabezado, y todo lo que incluye (correctamente, el orden de declaraciones en la unidad de traducción, después del preprocesamiento).

Según su comentario del 30 de mayo de 2011 a las 11:51 , en realidad quiere el comportamiento 1, pero esto no funciona, debido al problema 2. Puede obtener el comportamiento deseado al tener un encabezado separado que se incluye después de todos los demás (y completamente calificando el nombre en otros encabezados). Sin embargo, esto es frágil y, por lo tanto, desaconsejado, preferiblemente se reserva solo cuando se realiza la transición a espacios de nombres:

 //--- file myheader.hpp --- #include  namespace MyNamespace { ::boost::numeric::ublas::vector MyFunc(::boost::numeric::ublas::vector in); } //--- file myproject_last.hpp --- namespace MyNamespace { using ::boost::numeric::ublas::vector; } //--- file myproject.cpp --- #include "myheader.hpp" // ...other includes #include "myproject_last.hpp" 

Consulte GotW # 53: Migración a espacios de nombres para obtener más detalles, esta solución alternativa y consejos: “El espacio de nombres que utiliza declaraciones nunca debe aparecer en los archivos de encabezado”.

Es posible evitar el problema 1 agregando un espacio de nombre sin nombre alrededor de la statement de uso (para evitar que esos nombres sean visibles) y luego otra fuera del espacio de nombre sin nombre (para hacer que el nombre deseado sea visible), pero que todavía tenga problemas 2 y uglifies el encabezado:

 //--- file myheader.hpp --- #include  namespace MyNamespace { namespace { using ::boost::numeric::ublas::vector; vector MyFunc(vector in); } using MyFunc; // MyNamespace::(unique)::MyFunc > MyNamespace::MyFunc } 

Debido a estos problemas, solo debe usar using-declarations en archivos sin encabezado (.cc / .cpp): esto no afecta a otros archivos, por lo que se evita el problema 1; y todos los encabezados se han incluido, por lo que se evita el problema 2. En este caso, es una cuestión de gusto si los coloca en un espacio de nombres o no, ya que no afectan a otros archivos; es más seguro usar siempre nombres totalmente calificados en la statement de uso en sí (absoluta, comenzando con :: .

Lo más simple es colocar todas las declaraciones de uso en la parte superior del archivo, después de las inclusiones, pero fuera de los espacios de nombres: esto es seguro, no ambiguo, fácil de leer y permite usar los nombres en todo el archivo. Algunas desviaciones comunes:

  1. Usando-statement dentro de una función (o estructura o clase o bloque nested): bien . Esto minimiza el scope y es solo una cuestión de gusto: use-declaration está cerca del uso (legibility win), pero ahora están dispersos por todo el archivo (pérdida de legibilidad).
  2. Uso-statement con un nombre relativo dentro de un espacio de nombres (nombrado): propenso a errores . Esto es más conciso y agrega cierta claridad (nombres relacionados utilizados en el espacio de nombres al que se refieren), pero es potencialmente ambiguo (al igual que incluye con rutas relativas), y es más seguro evitar:

     using ::foo::bar; namespace foo { ... } namespace foo { // Implicitly ::foo:bar, could be ::bar, or ::other::foo::bar. using bar; } 
  3. Usando-statement con un nombre absoluto dentro de un espacio de nombres nombrado: sin sentido . Esto introduce el nombre solo en el espacio de nombres, pero no debería importarle, ya que no debería incluir el archivo .cc / .cpp:

     namespace foo { using ::bar; } 
  4. Uso-statement dentro de un espacio de nombres sin nombre: inútil, ligeramente peligroso . Por ejemplo, si tiene una función en un espacio de nombre sin nombre, digamos un detalle de implementación, entonces puede tener una statement de uso para su tipo de devolución o param types. Esto introduce el nombre en ese espacio de nombres (por lo que no puede referenciarse desde otros archivos), pero nuevamente, no debería importar, ya que no debería incluir el archivo .cc / .cpp (los espacios de nombres sin nombre son especialmente para evitar los conflictos de nombre en el tiempo del enlace, que no es aplicable aquí: es solo un alias en tiempo de comstackción). Peor aún, ¡introduce ambigüedad si ese nombre ya existe!