class A {};
int main() {
A() = A();
return 0;
}
ทำไมโค้ดนี้จึงคอมไพล์ ไม่ควรมีข้อผิดพลาดที่ทางด้านซ้ายของตัวดำเนินการกำหนดค่าควรวาง lvalue? A () lvalue คืออะไร? g ++ 4.7 เวอร์ชัน
class A {};
int main() {
A() = A();
return 0;
}
ทำไมโค้ดนี้จึงคอมไพล์ ไม่ควรมีข้อผิดพลาดที่ทางด้านซ้ายของตัวดำเนินการกำหนดค่าควรวาง lvalue? A () lvalue คืออะไร? g ++ 4.7 เวอร์ชัน
คำตอบ:
สำหรับในตัวชนิดที่คุณต้องการจะเป็นที่ถูกต้อง: ในตัวดำเนินการกำหนดต้องมีการปรับแก้lvalueทางด้านซ้ายมือ
อย่างไรก็ตามนี่ไม่ได้ใช้ตัวดำเนินการในตัว แต่เป็นการโอเวอร์โหลดที่คลาสประกาศโดยปริยาย นี่คือฟังก์ชันสมาชิกเทียบเท่ากับ
A().operator=(A());
และฟังก์ชั่นสมาชิกสามารถถูกเรียกบนrvalues
operator=ไม่ได้หมายความว่าoperator()) แต่ไม่เกี่ยวข้องกับคำถามมากนัก ตัวอย่างไม่ได้ทำอะไรกับผลลัพธ์ของงาน
A()ไม่เรียกมันสร้างวัตถุของการพิมพ์operator() A
หากคุณต้องการจริงๆคุณไม่สามารถรวบรวมด้วย C ++ 11 ได้:
class A {
template <typename T>
void operator=(T&&) && = delete; // no op= for rvalues
// generate other special members normally
A() = default;
A(A const&) = default;
A(A&&) = default;
~A() = default;
// op= only for lvalues
A& operator=(A&&) & = default;
A& operator=(A const&) & = default;
};
int main() {
A() = A(); // error
return 0;
}
( ตัวอย่างสด )
สังเกต&และ&&(aka ref-qualifiers) ในตอนท้ายของการประกาศของoperator=แบบฟอร์มต่างๆ สิ่งนี้ทำให้การประกาศเหล่านั้นถูกเลือกสำหรับ lvalues และ rvalues ตามลำดับ อย่างไรก็ตามเวอร์ชัน rvalue เมื่อเลือกโดยความละเอียดเกินจะทำให้โปรแกรมมีรูปแบบที่ไม่เหมาะสมเนื่องจากถูกลบ
อย่างไรก็ตามตัวดำเนินการที่สร้างขึ้นเริ่มต้น = ไม่มี ref-qualifier ใด ๆ ซึ่งหมายความว่าสามารถเรียกได้ทั้ง lvalues และ rvalues นั่นเป็นเหตุผลที่โค้ดในคำถามรวบรวมแม้ว่าจะA()เป็นค่า rvalue ก็ตาม
คอมไพเลอร์ C ++ จัดเตรียมคลาสทั้งหมดด้วยตัวสร้างเริ่มต้นนั่นคือสิ่งที่เกิดขึ้นตามรหัสของคุณเมื่อคุณพูดว่า A () = A (); เพียงแค่เรียกตัวสร้างด้วยอ็อบเจ็กต์นิรนามและฟังก์ชันจะส่งคืนการอ้างอิงไปยังอ็อบเจ็กต์ที่สร้างขึ้น (โดยนัย) แค่นั้นแหละ...