No entiendo por qué esto compila

80

Ciertamente me falta algo, pero no entiendo por qué esto se compila (con g ++ y clang ++):

struct A
{
};
struct B
{
};

int main()
{
  A a(B);
}

En primer lugar, Bes un tipo ... no un valor. ¿Cómo debo interpretar este código?

Picaud Vincent
fuente
37
Esto se conoce como el Parse más
irritante
8
@alterigel ¿Es realmente? En este caso no hay ambigüedad. Solo puede ser una declaración de función. No es lo A a(B());que podría ser una definición variable o una declaración de función.
nogal
8
Te sorprendería saber que struct A{}; int main() { A(foo); } compila tal cual , incluso si foono nombra nada.
Ayxan
20
@alterigel: este no es el análisis más irritante. Mire los ejemplos en la página a la que se vinculó. Esto es simplemente una declaración de función.
Pete Becker
3
@PeteBecker, podría ser mejor explicar por qué esto no es MVP en lugar de simplemente afirmar que no lo es, lo que creo que Walnut ya hizo anteriormente.
JPhi1618

Respuestas:

84

Se interpreta como la declaración de una función denominada a, que toma un argumento de tipo By devuelve A.

Brian
fuente
55
Y es por eso que es Most y Vexing. Una solución: (no es que realmente resuelva nada ya que expone la mala construcción)A a{B};
user4581301
23
@ user4581301 - es no más de análisis del disgusto. Es simplemente una declaración de función.
Pete Becker
23
Entonces resulta que es solo un análisis sobre todo irritante ...
MooseBoys
11
La parte más extraña al respecto es que C ++ no permite funciones anidadas, pero permite declaraciones dentro de una función.
The_Sympathizer
66
Suena como una buena motivación para agregar soporte para funciones anidadas a C ++; no solo serían útiles, sino que convertirían esta extraña verruga en un diseño razonable :)
Jeremy Friesner
15

Es simplemente una declaración de función que declara aser una función que regresa Ay toma un parámetro de tipo sin nombre B.

Es válido porque las declaraciones de función en lugar de las definiciones de función están permitidas dentro de las definiciones de función.

máquina_1
fuente
13

Este problema se conoce como el análisis más irritante . La línea A a(B);se puede interpretar como la declaración de una función llamada que adevuelve un objeto de tipo Ay toma un parámetro de tipo sin nombre B.

Una forma de evitar este problema es usar la sintaxis de inicialización uniforme que se introdujo en C ++ 11, que consiste en usar llaves en lugar de paréntesis: A a{B};devuelve un error. La línea ahora se interpreta como una declaración de variable inicializada con B, que es un tipo en lugar de un valor.

Aquí hay más información:

El análisis más irritante: cómo detectarlo y solucionarlo rápidamente

G. Morin
fuente
12
No creo que esto deba llamarse " análisis más irritante ". Es solo una declaración de función habitual, ya que también existe en C. No es necesaria una resolución de ambigüedad porque la línea solo puede ser una declaración de función, nada más. Mira tu enlace. Los ejemplos son todos diferentes de esto.
nogal
3
Si bien eso es cierto, está relacionado con el análisis más irritante. Es solo que esto también incluía un error tipográfico donde un nombre de tipo se usaba solo en lugar de una variable o una llamada de constructor, como probablemente fue la intención original.
Miral
1
Sí, "Most Vexing Parse" es una respuesta útil en este caso, a pesar de que el caso real en la pregunta es solo "Slightly Vexing Parse".
jpa
1
@wlanut: las estructuras vacías struct A { };no son válidas en el estándar C, incluso si algunos compiladores lo permiten. Suelta los frenos y no habría problema allí. Además, en C, declarar o definir struct Ano crea un nombre de tipo A(debe structagregarle el prefijo o agregarlo en typedef struct A A;algún lugar antes de Ausarlo sin el structprefijo). También en C, no hay un análisis alternativo a la declaración de función: el uso type name(...);simplemente no puede ser una definición variable; siempre es una declaración de función (o no válida). El código en la pregunta no es válido en C.
Jonathan Leffler