Je ne comprends pas pourquoi cela compile

80

Je manque certainement quelque chose, mais je ne comprends pas pourquoi cela se compile (avec à la fois g ++ et clang ++):

struct A
{
};
struct B
{
};

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

Tout d'abord, Bc'est un type ... pas une valeur. Comment dois-je interpréter ce code?

Picaud Vincent
la source
37
Ceci est connu comme l' analyse
alter igel
8
@alterigel Est-ce vraiment? Dans ce cas, il n'y a pas d'ambiguïté. Il ne peut s'agir que d'une déclaration de fonction. Ce n'est pas A a(B());ce qui pourrait être une définition de variable ou une déclaration de fonction.
noyer
8
Vous seriez surpris de savoir que struct A{}; int main() { A(foo); } compile tel quel , même s'il foone nomme rien.
Ayxan
20
@alterigel - ce n'est pas l'analyse la plus contrariante. Regardez les exemples sur la page à laquelle vous avez lié. Il s'agit simplement d'une déclaration de fonction.
Pete Becker
3
@PeteBecker, il pourrait être préférable d'expliquer pourquoi ce n'est pas MVP au lieu d'affirmer simplement que ce n'est pas le cas, ce que je crois que Walnut a déjà fait ci-dessus.
JPhi1618

Réponses:

84

Il est interprété comme la déclaration d'une fonction nommée a, qui prend un argument de type Bet retourne A.

Brian
la source
5
Et c'est pourquoi c'est Most et Vexing. Une solution: (pas qu'il résout réellement quoi que ce soit car il expose la mauvaise construction)A a{B};
user4581301
23
@ user4581301 - ce n'est pas l'analyse la plus contrariante. C'est simplement une déclaration de fonction.
Pete Becker
23
Donc, il s'avère que ce n'est qu'une analyse principalement vexante ...
MooseBoys
11
Le plus étrange partie à ce sujet est que C ++ ne permet pas de fonctions imbriquées, mais ne permet des déclarations à l' intérieur d' une fonction.
The_Sympathizer
6
Cela semble être une bonne motivation pour ajouter la prise en charge des fonctions imbriquées à C ++; non seulement ils seraient utiles, mais ils transformeraient cette verrue étrange en un design raisonnable :)
Jeremy Friesner
15

Il s'agit simplement d'une déclaration de fonction déclarant aêtre une fonction renvoyant Aet prenant un paramètre de type sans nom B.

Il est valide car les déclarations de fonction, par opposition aux définitions de fonction, sont autorisées dans les définitions de fonction.

machine_1
la source
13

Ce problème est connu comme l' analyse la plus contrariante . La ligne A a(B);peut être interprétée comme la déclaration d'une fonction nommée arenvoyant un objet de type Aet prenant un paramètre de type sans nom B.

Une façon d'éviter ce problème est d'utiliser la syntaxe d' initialisation uniforme introduite en C ++ 11, qui consiste à utiliser des accolades à la place des parenthèses: A a{B};renvoie une erreur. La ligne est maintenant interprétée comme une déclaration de variable initialisée avec B, qui est un type au lieu d'une valeur.

Voici plus d'informations:

L'analyse la plus contrariante: comment la repérer et la corriger rapidement

G. Morin
la source
12
Je ne pense pas que cela devrait être appelé "l' analyse la plus vexante ". C'est juste une déclaration de fonction habituelle comme elle existe également en C. Il n'y a pas de résolution d'ambiguïté nécessaire car la ligne ne peut être qu'une déclaration de fonction, rien d'autre. Regardez votre lien. Les exemples sont tous différents de cela.
noyer
3
Bien que cela soit vrai, c'est lié à l'analyse la plus vexante. C'est juste que cela incluait également une faute de frappe où un nom de type était utilisé seul au lieu d'une variable ou d'un appel de constructeur, comme c'était probablement l'intention d'origine.
Miral
1
Oui, "Most Vexing Parse" est une réponse utile dans ce cas, même si le cas réel de la question est juste "Slightly Vexing Parse".
jpa
1
@wlanut: Les structures vides struct A { };ne sont pas valides en C standard, même si certains compilateurs le permettent. Laissez tomber les accolades et il n'y aurait pas de problème là-bas. De plus, en C, déclarer ou définir struct Ane crée pas de nom de type A(vous devez le préfixer avec struct, ou ajouter typedef struct A A;quelque part avant Aest utilisé sans le structpréfixe). Toujours en C, il n'y a pas d'analyse alternative à la déclaration de fonction - l'utilisation type name(...);ne peut tout simplement jamais être une définition de variable; c'est toujours une déclaration de fonction (ou invalide). Le code dans la question n'est pas valide en C.
Jonathan Leffler