¿Por qué hay un nombre de clase inyectado?

147

Recientemente, vi una extraña característica de C ++: nombre de clase inyectado .

class X { };
X x1;
class X::X x2; // class X::X is equal to X
class X::X::X x3; // ...and so on...

Pero no puedo entender por qué esta característica es necesaria. ¿Hay alguna práctica que requiera esta función?

Y escuché que esta característica no existía en el antiguo C ++. Entonces, ¿cuándo fue presentado? C ++ 03? C ++ 11?

ikh
fuente
Amigo, ¿puedes mirar en Skype? No puedo alcanzarte
Irinel Iovan

Respuestas:

162

El nombre de la clase inyectada significa que Xse declara como miembro de X, por lo que la búsqueda de nombres en el interior Xsiempre encuentra la clase actual, no otra Xque pueda declararse en el mismo ámbito de cobertura, por ejemplo

void X() { }
class X {
public:
  static X create() { return X(); }
};

¿La create()función está creando un Xobjeto temporal o está llamando a la función X? En el ámbito del espacio de nombres llamaría a la función, por lo que el propósito del nombre de la clase inyectada es garantizar que dentro del cuerpo del Xnombre siempre encuentre la clase en sí misma (porque la búsqueda de nombres comienza en el propio ámbito de la clase antes de buscar en el adjunto alcance).

También es útil dentro de las plantillas de clase, donde el nombre de la clase inyectada se puede usar sin una lista de argumentos de plantilla, por ejemplo, usando simplemente en Foolugar de la plantilla completa de identificación Foo<blah, blah, blah>, por lo que es fácil referirse a la instanciación actual. Ver DR 176 para un cambio entre C ++ 98 y C ++ 03 que lo aclaró.

La idea del nombre de la clase inyectada estaba presente en C ++ 98, pero la terminología era nueva para C ++ 03.

C ++ 98 dice:

Se inserta un nombre de clase en el ámbito en el que se declara inmediatamente después de ver el nombre de clase . El nombre de la clase también se inserta en el ámbito de la clase misma.

El DR 147 cambió la segunda oración, por lo que C ++ 03 dice en [clase] / 2:

Se inserta un nombre de clase en el ámbito en el que se declara inmediatamente después de ver el nombre de clase . El nombre de la clase también se inserta en el ámbito de la clase misma; Esto se conoce como el nombre de la clase inyectada .

Incluso antes de C ++ 98, el ARM tiene una redacción más o menos equivalente que significa que el nombre de la clase siempre se puede usar en el cuerpo de la clase para referirse a la clase misma:

El nombre de una clase se puede usar como un nombre de clase incluso dentro de la lista de miembros del especificador de clase.

  • Por ejemplo,

    class link { link* next; };

Jonathan Wakely
fuente
2
Me preguntaron eso con bastante frecuencia, pero nunca pude construir un ejemplo simple que señalara el problema. Entonces +1 para el ejemplo.
dhein
1
Esto se puede ver claramente si ejecuta clang ++ your_program.cpp -Xclang -ast-dump y ve su clase y luego un nodo hijo de clase inyectado.
xaxxon