Comment «int main () {(([] () {}) ());}» est-il valide en C ++?

271

J'ai récemment rencontré le morceau de code ésotérique suivant.

int main(){(([](){})());}

Reformatez-le comme suit pour le rendre plus lisible:

int main(){
    (([](){})());   //  Um... what?!?!
}

Mais je ne peux pas comprendre comment (([](){})())est un code valide.

  • Il ne ressemble pas à la syntaxe du pointeur de fonction.
  • Cela ne peut pas être une astuce de surcharge de l'opérateur. Le code se compile tel quel.

Google n'a pas beaucoup aidé avec cette recherche de tous les symboles. Mais il se compile dans Visual Studio 2010 et ne produit rien. Il n'y a eu aucune erreur et aucun avertissement. Cela ressemble donc à du code valide.

Je ne l' ai jamais vu un code valide qui est si bizarre à l' extérieur de Javascript et des pointeurs de fonction C .

Quelqu'un peut-il expliquer en quoi c'est un C ++ valide?

Mysticial
la source
94
Hey! C'est à moi. "Don't sweat it. We have int main(){(([](){})());} which is valid C++" (9 novembre dans le chat)
sehe
31
c'est une fermeture lambda c ++ 11
7
@Mysticial - Ce code vous mystifie car il est inutile. Si ce lambda ferait quelque chose, vous reconnaîtriez qu'il a une syntaxe similaire aux pointeurs de fonction (avec laquelle il est étroitement lié).
SChepurin
14
@Mysticial - "6 ans de C ++" - les lambdas viennent d'être ajoutés en C ++ 11, donc personne ne les a expérimentés avant il y a environ un an.
Pete Becker
50
L'URL ici est assez amusante: "how-is-int-main-valid-c"
tckmn

Réponses:

283

Le code appelle essentiellement un lambda vide.

Commençons par le début: [](){}est une expression lambda vide .

Ensuite, en C et C ++, vous pouvez encapsuler des expressions dans des parens et elles se comportent exactement de la même manière que si elles étaient écrites sans elles, c'est donc ce que fait la première paire de parens autour du lambda. Nous y sommes maintenant ([](){}).

Ensuite, ()après le premier wrapping, la parens appelle la lambda (vide). Nous en sommes maintenant à([](){})()

L'expression entière est à nouveau enveloppée de parens et nous obtenons (([](){})()).

Enfin, ;termine la déclaration. Nous arrivons à (([](){})());.


† Il y a des cas d'angle au moins en C ++, comme avec T a_var; il y a une différence entre decltype(a_var)etdecltype((a_var)) .

Xeo
la source
7
Manqué un poignard.
R. Martinho Fernandes
33
@ R.MartinhoFernandes: Il était toujours coincé chez quelqu'un, donc j'ai dû aller le récupérer.
Xeo
1
J'allais voter pour avoir correctement mentionné le cas où l'ajout () autour d'une expression modifie la sémantique. Mais je me suis alors rappelé que cela n'avait aucun rapport avec la question, vraiment. Belle réponse
sehe
2
Les parenthèses changent également la signification d'un programme dans le cas de la désambiguïsation de l'analyse la plus vexante: B foo(A())foo est une fonction (en prenant un pointeur pour fonctionner comme seul paramètre et en retournant un B) tandis que dans B foo((A()))foo est un objet B construit invoquant un constructeur prenant a Un objet (dont l'instance est un temporaire anonyme dans ce cas).
Annonce N
1
@AdN: Ce n'est plus une expression, mais une déclaration.
Xeo