Bagaimana "int main () {(([] () {}) ());}" C ++ valid?

271

Baru-baru ini saya menemukan potongan kode esoterik berikut.

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

Format ulang sebagai berikut untuk membuatnya lebih mudah dibaca:

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

Tapi saya tidak bisa mengerti bagaimana (([](){})())kode yang valid.

  • Itu tidak terlihat seperti sintaks fungsi pointer.
  • Tidak mungkin ada trik kelebihan operator. Kode mengkompilasi apa adanya.

Google tidak banyak membantu dengan pencarian semua simbol ini. Tapi itu dikompilasi dalam Visual Studio 2010 dan tidak menghasilkan apa-apa. Tidak ada kesalahan, dan tidak ada peringatan. Jadi sepertinya kode yang valid.

Aku belum pernah melihat kode yang valid yang begitu aneh di luar Javascript dan C fungsi pointer .

Bisakah seseorang menjelaskan bagaimana ini valid C ++?

Mistikal
sumber
94
Hei! Itu milikku. "Don't sweat it. We have int main(){(([](){})());} which is valid C++" (9 Nov dalam obrolan)
lihat
31
itu adalah penutupan c ++ 11 lambda
7
@Mysticial - Kode ini membingungkan Anda karena tidak berguna. Jika lambda ini akan melakukan sesuatu, Anda akan mengenalinya memiliki sintaksis yang mirip dengan pointer fungsi (yang terkait erat).
SChepurin
14
@Mysticial - "6 tahun C ++" - lambdas baru saja ditambahkan di C ++ 11, jadi tidak ada yang punya pengalaman dengan mereka sebelum satu tahun yang lalu.
Pete Becker
50
URL di sini cukup menghibur: "how-is-int-main-valid-c"
tckmn

Jawaban:

283

Kode dasarnya memanggil lambda kosong.

Mari kita mulai dari awal: [](){}adalah ekspresi lambda kosong .

Kemudian, dalam C dan C ++, Anda dapat membungkus ekspresi dalam parens dan mereka berperilaku persis sama seolah-olah ditulis tanpa mereka, jadi itulah yang dilakukan sepasang parens pertama di sekitar lambda. Kami sekarang di([](){}) .

Kemudian, ()setelah orangtua pembungkus pertama memanggil lambda (kosong). Kami sekarang di([](){})()

Seluruh ekspresi dibungkus dalam parens lagi dan kita dapatkan (([](){})()) .

Akhirnya, ;akhiri pernyataan itu. Kami tiba di (([](){})());.


† Ada beberapa kasus sudut setidaknya dalam C ++, seperti T a_var; ada perbedaan antara decltype(a_var)dandecltype((a_var)) .

Xeo
sumber
7
Melewatkan belati.
R. Martinho Fernandes
33
@ R.MartinhoFernandes: Itu masih macet di seseorang, jadi saya harus pergi dan mengambilnya.
Xeo
1
Saya akan memilih dengan tepat menyebutkan kasus di mana menambahkan () di sekitar ekspresi mengubah semantik. Tapi kemudian saya ingat bahwa tidak ada hubungannya dengan pertanyaan, sungguh. Jawaban yang bagus
lihat
2
Tanda kurung juga mengubah arti program dalam kasus disambiguasi parse yang paling menjengkelkan: B foo(A())foo adalah fungsi (mengambil pointer berfungsi sebagai hanya parameter dan mengembalikan B) sedangkan di B foo((A()))foo adalah objek B dibangun memohon pengambilan konstruktor a A object (instance mana yang bersifat anonim sementara dalam kasus ini).
Iklan N
1
@ ADN: Itu bukan ekspresi lagi, tapi deklarasi.
Xeo