c++ - funcion - alcance del uso de la declaración dentro de un espacio de nombres
funcion estatica ejemplos (5)
¿Es seguro (y correcto) en un archivo de encabezado C ++ usar la declaración using dentro de un espacio de nombres de la siguiente manera:
#include <boost/numeric/ublas/vector.hpp>
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?
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.
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 declaración 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 declaración, el comportamiento exacto dependerá del orden de los encabezados que incluya antes de la declaración (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 compilació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.
Editar: consulte Migración a espacios de nombres para ver ejemplos y el problema descrito en profundidad.
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:
- Introducen un nombre en el espacio de nombres, que afecta a todos los archivos que incluyen el encabezado.
- 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:
- Dentro de
MyNamespace
, elvector
ahora puede resolver paraboost::numeric::ublas::vector
, para cualquier archivo que incluya este encabezado: "contamina" el espacio de nombresMyNamespace
. - Qué
boost::numeric::ublas::vector
declaracionesboost::numeric::ublas::vector
se importan depende de qué declaraciones aparecen antes de esta declaración 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 <boost/numeric/ublas/vector.hpp>
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 declaración 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 aún tenga problemas 2 y uglifies el encabezado:
//--- file myheader.hpp ---
#include <boost/numeric/ublas/vector.hpp>
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 declaración 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:
- Usando-declaración dentro de una función (o estructura o clase o bloque anidado): bien . Esto minimiza el alcance 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).
Uso-declaración 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; }
Usando-declaración 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; }
Uso-declaración 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 declaración 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 compilación). Peor aún, ¡introduce ambigüedad si ese nombre ya existe!
Una declaración de uso es, como su nombre lo dice, una declaración. Todas las declaraciones tienen un alcance en el bloque adjunto (7.2), en este caso el espacio de nombres MyNamespace
. No será visible fuera de ese espacio de nombres.