c++ - declarations - ¿Por qué inline espacios de nombres sin nombre?
using declarations c++ (2)
Una rápida para los gurús: C ++ 11 permite que los espacios de nombres sin nombre se declaren en inline
. Esto me parece redundante; las cosas declaradas en un espacio de nombres sin nombre ya se usan como si estuvieran declaradas en el espacio de nombres adjunto.
Así que mi pregunta es la siguiente: ¿qué significa decir?
inline namespace /*anonymous*/ {
// stuff
}
¿Y en qué se diferencia de lo tradicional?
namespace /*anonymous*/ {
// stuff
}
Que sabemos y amamos de C ++ 98? ¿Alguien puede dar un ejemplo de comportamiento diferente cuando se usa inline
?
EDIT: Solo para aclarar, ya que esta pregunta ha sido marcada como un duplicado: no estoy preguntando acerca de los espacios de nombres en línea nombrados en general. Entiendo el caso de uso allí, y creo que son geniales. Específicamente, estoy preguntando qué significa declarar un espacio de nombres sin nombre como en inline
. Dado que los espacios de nombres sin nombre son necesariamente siempre locales a un TU, el simulacro de control de versiones no parece aplicarse, así que tengo curiosidad por lo que realmente hace la adición de inline
.
Además, el estándar [7.3.1.1], con respecto a los espacios de nombres sin nombre, dice:
aparece en
inline
si y solo si aparece en la definición de espacio de nombres sin nombre
pero esto parece ser una tautología para los ojos de mis abogados que no hablan idiomas: "aparece en la definición si aparece en la definición"! Para obtener puntos de bonificación, ¿puede alguien explicar lo que realmente dice este bit de standardese?
EDIT: Cubbi reclamó el punto de bonificación en los comentarios:
la norma dice que la definición de espacio de nombres sin nombre se comporta como si fuera reemplazada por X, donde aparece en
inline
en X si aparece en la definición de espacio de nombres sin nombre
Aquí hay un uso que he encontrado:
namespace widgets { inline namespace {
void foo();
} } // namespaces
void widgets::foo()
{
}
En este ejemplo, foo
tiene vínculos internos y podemos definir la función más adelante usando la sintaxis de namespace::function
para asegurarnos de que la firma de la función es correcta. Si no utilizara el espacio de nombres de los widgets
, la definición void foo()
definiría una función totalmente diferente. Tampoco es necesario que vuelva a abrir el espacio de nombres, lo que le permite tener un nivel de sangría.
Si ya hay otra función llamada foo
en el namespace
los widgets, esto le dará una ambigüedad en lugar de una violación de ODR desagradable.
No sé si ya está hecho para responder tu propia pregunta en SO, pero después de jugar un poco, mi curiosidad se ha satisfecho, así que es mejor que la comparta.
La definición de un espacio de nombres en línea incluye no solo el alzamiento de nombres en el espacio de nombres que lo contiene (lo que ocurre de todos modos con los espacios de nombres sin nombre), sino que también permite que las plantillas definidas dentro de un espacio de nombres en línea se especialicen fuera de él. Resulta que esto también se aplica a los espacios de nombres sin nombre:
inline // comment this out to change behaviour
namespace {
template <typename T> struct A {};
}
template <> struct A<int> {};
Sin la inline
, g ++ se queja de intentar especializar una plantilla de un espacio de nombres diferente (aunque Clang no lo hace). Con inline
, compila bien. Con ambos compiladores, todo lo definido dentro de la especialización todavía está marcado como que tiene un enlace interno (según nm
), como si estuviera dentro del espacio de nombres sin nombre, pero supongo que esto es de esperar. Realmente no puedo pensar en ninguna razón por la que esto sea útil, pero ahí vamos.
Un efecto posiblemente más útil proviene del cambio con respecto a la búsqueda dependiente de argumentos para los espacios de nombres en línea, que también afecta a los espacios de nombres en línea sin nombre. Considere el siguiente caso:
namespace NS {
// Pretend this is defined in some header file
template <typename T>
void func(const T&) {}
// Some type definition private to this TU
inline namespace {
struct A {};
}
} // end namespace NS
int main()
{
NS::A a;
func(a);
}
Sin la inline
, ADL falla y tenemos que escribir explícitamente NS::func(a)
. Por supuesto, si definimos el espacio de nombres sin nombre en el nivel superior (como lo haría normalmente), entonces no obtendríamos ADL si estaba en línea o no, pero aún así ...