“ int main () {(([] () {}) ());}” ใช้ได้อย่างไร ++


271

ฉันเพิ่งเจอชิ้นส่วนที่ลึกลับของรหัสต่อไปนี้

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

จัดรูปแบบใหม่ดังต่อไปนี้เพื่อให้อ่านง่ายขึ้น:

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

แต่ฉันไม่เข้าใจว่า(([](){})())รหัสถูกต้องอย่างไร

  • มันดูเหมือนไวยากรณ์ตัวชี้ฟังก์ชันไม่ได้
  • มันไม่สามารถเป็นกลอุบายการบรรทุกเกินพิกัดบางอย่างได้ รหัสคอมไพล์ตามที่เป็นอยู่

Google ไม่ได้ช่วยอะไรมากนักในการค้นหาสัญลักษณ์ทั้งหมด แต่มันก็คอมไพล์ใน Visual Studio 2010 และไม่มีผลอะไร ไม่มีข้อผิดพลาดและไม่มีคำเตือน ดังนั้นดูเหมือนรหัสที่ถูกต้อง

ผมไม่เคยเห็นรหัสที่ถูกต้องใด ๆ ที่อยู่นอกมหัศจรรย์ของJavascriptและC คำแนะนำการทำงาน

บางคนสามารถอธิบายได้ว่าวิธีนี้ใช้ได้อย่างไร C ++


94
เฮ้! นั่นคือของฉัน "Don't sweat it. We have int main(){(([](){})());} which is valid C++" (แชท 9 พ.ย. )
sehe

31
มันเป็นการปิดแลมบ์ดา c ++ 11

7
@Mysticial - รหัสนี้ทำให้คุณประหลาดใจเพราะไม่มีประโยชน์ หากแลมบ์ดานี้จะทำอะไรคุณจะรู้ว่ามันมีรูปแบบคล้ายกับพอยน์เตอร์ของฟังก์ชั่น (ซึ่งมันเกี่ยวข้องอย่างใกล้ชิด)
SChepurin

14
@Mysticial - "6 ปีของ C ++" - lambdas เพิ่งถูกเพิ่มเข้ามาใน C ++ 11 ดังนั้นจึงไม่มีใครมีประสบการณ์กับพวกมันมาก่อนหนึ่งปีหรือมากกว่านั้น
Pete Becker

50
URL ที่นี่ค่อนข้างน่าขบขัน: "how-is-int-main-valid-c"
tckmn

คำตอบ:


283

รหัสเป็นหลักเรียกแลมบ์ดาที่ว่างเปล่า

เริ่มต้น Let 's จากจุดเริ่มต้น: [](){}เป็นที่ว่างเปล่าแสดงออกแลมบ์ดา

จากนั้นใน C และ C ++ คุณสามารถห่อนิพจน์ใน parens และพวกมันจะทำงานเหมือนกับที่เขียนโดยไม่มีพวกเขานั่นคือสิ่งที่ parens คู่แรกรอบแลมบ์ดาทำ ([](){})เราตอนนี้ที่

จากนั้น()หลังจากการตัดคำแรกห่อหุ้มเรียกแลมบ์ดา (ว่าง) ตอนนี้เราอยู่ที่([](){})()

การแสดงออกทั้งหมดจะถูกห่อใน parens (([](){})())อีกครั้งและเราได้รับ

ในที่สุดก็;จบคำสั่ง (([](){})());เรามาถึงที่


†มีบางกรณีมุมอย่างน้อยใน C ++, เช่นเดียวกับการT a_var; มีความแตกต่างระหว่างdecltype(a_var)decltype((a_var))และ


7
พลาดกริช
R. Martinho Fernandes

33
@ R.MartinhoFernandes: มันยังคงติดอยู่ในบางคนดังนั้นฉันต้องไปและดึง
Xeo

1
ฉันจะ upvote อย่างถูกต้องสำหรับการพูดถึงกรณีที่การเพิ่ม () รอบนิพจน์เปลี่ยนความหมาย แต่ฉันจำได้ว่าไม่มีความเกี่ยวข้องกับคำถามจริงๆ คำตอบที่ดี
sehe

2
ในวงเล็บยังเปลี่ยนความหมายของโปรแกรมในกรณีของการแยกวิเคราะห์ที่รบกวนมากที่สุด: B foo(A())foo เป็นฟังก์ชั่น (การใช้ตัวชี้เพื่อทำหน้าที่เป็นพารามิเตอร์เท่านั้นและส่งคืน B) ในขณะที่B foo((A()))foo เป็นวัตถุ B วัตถุ A (ซึ่งอินสแตนซ์ใดเป็นการชั่วคราวแบบไม่ระบุชื่อในกรณีนี้)
โฆษณา N

1
@AdN: นั่นไม่ใช่การแสดงออกอีกต่อไป แต่เป็นการประกาศ
Xeo
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.