ฉันไม่เข้าใจว่าทำไมการรวบรวมนี้


80

ฉันขาดอะไรบางอย่างไปแล้ว แต่ฉันไม่เข้าใจว่าทำไมการคอมไพล์นี้ (ทั้ง g ++ และ clang ++):

struct A
{
};
struct B
{
};

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

ประการแรกBคือประเภท ... ไม่ใช่ค่า ฉันควรตีความรหัสนี้อย่างไร


37
สิ่งนี้เป็นที่รู้จักกันในชื่อ The Vexing Parse
แก้ไข igel

8
@alterigel มันจริงเหรอ? ในกรณีนี้ไม่มีความกำกวม มันสามารถประกาศฟังก์ชั่นเท่านั้น ไม่ใช่A a(B());ซึ่งอาจเป็นคำจำกัดความของตัวแปรหรือการประกาศฟังก์ชัน
วอลนัต

8
คุณจะแปลกใจที่รู้ว่าstruct A{}; int main() { A(foo); } คอมไพล์ดังที่เป็นอยู่แม้ว่าfooจะไม่ได้ตั้งชื่ออะไรก็ตาม
Ayxan

20
@alterigel - นี่ไม่ใช่การแยกวิเคราะห์ที่น่ารำคาญที่สุด ดูตัวอย่างในหน้าเว็บที่คุณเชื่อมโยง นี่เป็นเพียงการประกาศฟังก์ชั่น
Pete Becker

3
@PeteBecker มันอาจจะดีกว่าที่จะอธิบายว่าทำไมมันถึงไม่ใช่ MVP แทนที่จะแค่ยืนยันว่ามันไม่ใช่ซึ่งฉันเชื่อว่าวอลนัทได้ทำไปแล้ว
JPhi1618

คำตอบ:


84

ก็ตีความว่าเป็นคำประกาศของฟังก์ชั่นที่มีชื่อaซึ่งจะใช้เวลาหนึ่งอาร์กิวเมนต์ชนิดและผลตอบแทนBA


5
และนี่คือเหตุผลว่าทำไมจึงเป็นส่วนใหญ่และ Vexing วิธีการแก้ปัญหา: (ไม่ใช่ว่ามันจะแก้อะไรจริง ๆ เพราะมันทำให้การก่อสร้างไม่ดี)A a{B};
4581301

23
@ user4581301 - ไม่ใช่การแยกวิเคราะห์ที่น่ารำคาญที่สุด มันเป็นเพียงการประกาศฟังก์ชั่น
Pete Becker

23
ดังนั้นมันจะเปิดออกมาเป็นเพียงส่วนใหญ่แจงรบกวน ...
MooseBoys

11
ส่วนที่แปลกประหลาดเกี่ยวกับมันว่า C ++ ไม่อนุญาตให้มีฟังก์ชั่นที่ซ้อนกัน แต่ไม่อนุญาตให้มีการประกาศภายในฟังก์ชั่น
The_Sympathizer

6
ฟังดูเหมือนเป็นแรงจูงใจที่ดีสำหรับการเพิ่มการสนับสนุนสำหรับฟังก์ชันซ้อนใน C ++; ไม่เพียง แต่พวกเขาจะมีประโยชน์เท่านั้น แต่พวกเขาจะเปลี่ยนหูดที่แปลกใหม่ให้กลายเป็นรูปแบบที่เหมาะสม :)
Jeremy Friesner

15

มันเป็นเพียงการประกาศฟังก์ชั่นที่ประกาศว่าaเป็นฟังก์ชันที่ส่งคืนAและรับพารามิเตอร์ชนิดที่ไม่มีชื่อหนึ่งBรายการ

มันถูกต้องเพราะการประกาศฟังก์ชั่นซึ่งตรงข้ามกับคำจำกัดความของฟังก์ชั่นที่ได้รับอนุญาตภายในนิยามฟังก์ชั่น


13

ปัญหานี้เป็นที่รู้จักกันแจงรบกวนมากที่สุด บรรทัดที่A a(B);สามารถตีความได้ว่าการประกาศของฟังก์ชั่นที่มีชื่อaกลับวัตถุของการพิมพ์และการใช้พารามิเตอร์ชื่อประเภทAB

วิธีหนึ่งในการหลีกเลี่ยงปัญหานี้คือการใช้ไวยากรณ์การกำหนดค่าเริ่มต้นที่เหมือนกันซึ่งเปิดตัวใน C ++ 11 ซึ่งประกอบด้วยการใช้วงเล็บปีกกาแทนวงเล็บ: A a{B};ส่งคืนข้อผิดพลาด ตอนนี้บรรทัดถูกตีความเป็นการประกาศตัวแปรที่กำหนดค่าเริ่มต้นด้วยBซึ่งเป็นชนิดแทนที่จะเป็นค่า

นี่คือข้อมูลเพิ่มเติม:

The Vexing Parse ที่มากที่สุด: วิธีการระบุและแก้ไขได้อย่างรวดเร็ว


12
ฉันไม่คิดว่านี้ควรจะเรียกว่า " ส่วนใหญ่ที่รบกวนแจง " มันเป็นเพียงการประกาศฟังก์ชั่นปกติตามที่มันมีอยู่ใน C. ไม่จำเป็นต้องมีการแก้ปัญหาความกำกวมเนื่องจากบรรทัดสามารถเป็นการประกาศฟังก์ชันได้เท่านั้น ดูลิงค์ของคุณ ตัวอย่างทั้งหมดแตกต่างจากนี้
walnut

3
ในขณะที่มันเป็นจริงมันมีความเกี่ยวข้องกับการแยกวิเคราะห์ที่น่ารำคาญที่สุด เป็นเพียงแค่นี้ยังรวมถึงการพิมพ์ผิดที่ชื่อประเภทถูกใช้เพียงอย่างเดียวแทนตัวแปรหรือการเรียกคอนสตรัคเตอร์ตามที่อาจเป็นเจตนาดั้งเดิม
Miral

1
ใช่ "Vexing Parse ส่วนใหญ่" เป็นคำตอบที่มีประโยชน์ในกรณีนี้แม้ว่ากรณีที่เกิดขึ้นจริงในคำถามนั้นเป็นเพียง "Slightly Vexing Parse"
jpa

1
@wlanut: โครงสร้างว่างเปล่าstruct A { };ไม่ถูกต้องในมาตรฐาน C แม้ว่าคอมไพเลอร์บางตัวจะอนุญาต วางเครื่องมือจัดฟันและจะไม่มีปัญหาเกิดขึ้น นอกจากนี้ใน C การประกาศหรือการกำหนดstruct Aไม่ได้สร้างชื่อประเภทA(คุณต้องใส่คำนำหน้าด้วยstructหรือเพิ่มtypedef struct A A;บางส่วนก่อนที่Aจะใช้โดยไม่มีstructคำนำหน้า) นอกจากนี้ใน C ไม่มีการแยกวิเคราะห์ทางเลือกในการประกาศฟังก์ชั่น - การใช้type name(...);เพียงแค่ไม่สามารถเป็นคำจำกัดความของตัวแปร; มันมักจะประกาศฟังก์ชั่น (หรือไม่ถูกต้อง) รหัสในคำถามไม่ถูกต้องใน C.
Jonathan Leffler
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.