ทำไมคนแรกถึงกลับมาอ้างอิง?
int x = 1;
int y = 2;
(x > y ? x : y) = 100;
ในขณะที่สองไม่ได้?
int x = 1;
long y = 2;
(x > y ? x : y) = 100;
อันที่จริงที่สองไม่ได้รวบรวมเลย - "ไม่ lvalue ซ้ายของการมอบหมาย"
ทำไมคนแรกถึงกลับมาอ้างอิง?
int x = 1;
int y = 2;
(x > y ? x : y) = 100;
ในขณะที่สองไม่ได้?
int x = 1;
long y = 2;
(x > y ? x : y) = 100;
อันที่จริงที่สองไม่ได้รวบรวมเลย - "ไม่ lvalue ซ้ายของการมอบหมาย"
คำตอบ:
นิพจน์ไม่มีประเภทผลตอบแทน แต่มีประเภทและเนื่องจากเป็นที่รู้จักในมาตรฐาน C ++ ล่าสุด - หมวดค่า
นิพจน์เงื่อนไขสามารถเป็นlvalueหรือrvalue นี่คือหมวดค่าของมัน (นี่คือการทำให้เข้าใจง่าย, ในC++11
เรามี lvalues, xvalues และ prvalues)
ในแง่กว้างและเรียบง่ายlvalueหมายถึงวัตถุในหน่วยความจำและrvalueเป็นเพียงค่าที่อาจไม่จำเป็นต้องแนบกับวัตถุในหน่วยความจำ
การแสดงออกที่ได้รับมอบหมายกำหนดมูลค่าให้กับวัตถุดังนั้นสิ่งที่ได้รับมอบหมายให้จะต้องเป็นlvalue
สำหรับการแสดงออกเงื่อนไข ( ?:
) จะเป็นlvalue (อีกครั้งในวงกว้างและแง่ง่าย) ที่สองและสามตัวถูกดำเนินการจะต้องเป็นlvaluesประเภทเดียวกัน นี่เป็นเพราะประเภทและประเภทค่าของนิพจน์เงื่อนไขถูกกำหนดในเวลารวบรวมและต้องเหมาะสมว่าเงื่อนไขเป็นจริงหรือไม่ หากหนึ่งในตัวถูกดำเนินการจะต้องมีการแปลงเป็นชนิดที่แตกต่างกันเพื่อให้ตรงกับอื่น ๆ แล้วการแสดงออกเงื่อนไขไม่สามารถเป็นlvalueเป็นผลมาจากการแปลงนี้จะไม่เป็นlvalue
ข้อมูลอ้างอิง ISO / IEC 14882: 2011:
3.10 [basic.lval] ค่าและค่า (เกี่ยวกับหมวดค่า)
5.15 [expr.cond] โอเปอเรเตอร์แบบมีเงื่อนไข (กฎสำหรับประเภทและค่าประเภทที่นิพจน์เงื่อนไขมี)
5.17 [expr.ass] การกำหนดและตัวดำเนินการมอบหมายผสม (ข้อกำหนดว่า lhs ของการมอบหมายต้องเป็นค่า lvalue ที่สามารถแก้ไขได้)
an rvalue is just a value that may not necessarily be *attached* to an object in memory.
คุณช่วยอธิบายสิ่งนี้ในระยะที่ง่ายขึ้นได้ไหม? . คุณหมายถึงtype and value *category*
อะไร. ขอบคุณ
prvalue, xvalue, glvalue
เป็นหมวดหมู่ค่า
true
, this
, enum
ค่า สิ่งเหล่านั้นมีค่ามากมาย ("บริสุทธิ์" rvalues) แต่ไม่ได้อยู่ในความทรงจำ
ชนิดของ?:
นิพจน์ประกอบไปด้วยเป็นประเภททั่วไปของอาร์กิวเมนต์ที่สองและสาม หากทั้งสองประเภทเหมือนกันคุณจะได้รับการอ้างอิงกลับ หากพวกเขาสามารถแลกเปลี่ยนกันได้หนึ่งคนได้รับเลือกและคนอื่น ๆ ได้รับการแปลง (เลื่อนตำแหน่งในกรณีนี้) เนื่องจากคุณไม่สามารถส่งคืนการอ้างอิง lvalue ไปยังชั่วคราว (ตัวแปรที่ถูกแปลง / เลื่อนระดับ), ประเภทของมันจึงเป็นประเภทค่า
มันไม่สามารถส่งคืนค่าlvalue ได้เนื่องจากจะต้องส่งเสริมประเภทของx
การจับคู่กับชนิดของimplicitly y
(เนื่องจากทั้งสองด้าน:
ไม่ใช่ประเภทเดียวกัน) และต้องสร้างชั่วคราว
นิพจน์ 5.17 การกำหนดและตัวดำเนินการกำหนดผสม
5.17 / 3
หากตัวถูกดำเนินการตัวที่สองและที่สามมีประเภทที่แตกต่างกันและมีประเภทคลาส (อาจเป็น cv ที่ผ่านการรับรอง) จะมีความพยายามในการแปลงตัวถูกดำเนินการแต่ละตัวเป็นประเภทอื่น กระบวนการในการพิจารณาว่านิพจน์ตัวถูกดำเนินการ E1 ประเภท T1 สามารถแปลงให้ตรงกับนิพจน์ตัวถูกดำเนินการ E2 ประเภท T2 ถูกกำหนดดังนี้:
- หาก E2 เป็น lvalue: E1 สามารถแปลงให้ตรงกับ E2 หาก E1 สามารถแปลงได้โดยปริยาย (ข้อ 4) เป็นประเภท“ การอ้างอิงถึง T2” โดยขึ้นอยู่กับข้อ จำกัด ที่ในการแปลงการอ้างอิงต้องผูกโดยตรง (8.5.3) ) ถึง E1
- หาก E2 เป็นค่า rvalue หรือหากการแปลงข้างต้นไม่สามารถทำได้:
- ถ้า E1 และ E2 มีประเภทชั้นเรียนและประเภทชั้นพื้นฐานเหมือนกันหรือหนึ่งเป็นชั้นฐานของอื่น ๆ : E1 สามารถแปลงให้ตรงกับ E2 ถ้าชั้นของ T2 เป็นประเภทเดียวกันเป็นหรือชั้นฐานของ คลาสของ T1 และคุณสมบัติ cv ของ T2 เป็นคุณสมบัติของ cv เดียวกันกับที่หรือคุณสมบัติของ cv-qualification ที่มากกว่าของ cv-qualification ของ T1 หากมีการใช้การแปลง E1 จะเปลี่ยนเป็น rvalue ประเภท T2 ที่ยังคงอ้างอิงถึงวัตถุคลาสต้นฉบับ (หรือ subobject ที่เหมาะสมของมัน) [ หมายเหตุ: นั่นคือไม่มีการคัดลอก - หมายเหตุท้าย ] โดยการคัดลอกเริ่มต้นชั่วคราวของประเภท T2 จาก E1 และใช้ชั่วคราวนั้นเป็นตัวถูกดำเนินการแปลง
มิฉะนั้น (เช่นถ้า
E1
หรือ E2 มีประเภทคลาสที่ไม่ใช่หรือถ้าพวกเขาทั้งสองมีประเภทชั้นเรียน แต่ชั้นเรียนพื้นฐานไม่เหมือนกันหรือเป็นหนึ่งในชั้นฐานของอื่น ๆ ): E1 สามารถแปลงให้ตรงกับ E2 ถ้า E1 สามารถ แปลงเป็นประเภทที่นิพจน์ E2 มีโดยปริยายหาก E2 ถูกแปลงเป็น rvalue (หรือเป็นประเภทที่มีหาก E2 เป็น rvalue)การใช้กระบวนการนี้จะถูกกำหนดว่าตัวถูกดำเนินการตัวที่สองสามารถแปลงให้ตรงกับตัวถูกดำเนินการตัวที่สามและตัวถูกดำเนินการตัวที่สามสามารถแปลงให้ตรงกับตัวถูกดำเนินการตัวที่สองหรือไม่ หากทั้งสองสามารถแปลงหรือหนึ่งสามารถแปลง แต่การแปลงไม่ชัดเจนโปรแกรมจะเกิดขึ้นไม่ดี หากไม่สามารถแปลงได้ตัวถูกดำเนินการจะไม่เปลี่ยนแปลงและทำการตรวจสอบเพิ่มเติมตามที่อธิบายไว้ด้านล่าง หากการแปลงเป็นไปได้อย่างแน่นอนการแปลงนั้นจะถูกนำไปใช้กับตัวถูกดำเนินการที่เลือกและตัวถูกดำเนินการแปลงถูกนำมาใช้แทนตัวถูกดำเนินการเดิมสำหรับส่วนที่เหลือของส่วนนี้
5.17 / 4
หากตัวถูกดำเนินการตัวที่สองและสามเป็น lvalues และมีชนิดเดียวกันผลลัพธ์จะเป็นชนิดนั้นและเป็น lvalue และเป็นบิตฟิลด์ถ้าตัวถูกดำเนินการตัวที่สองหรือสามเป็นบิตฟิลด์หรือทั้งสองเป็นบิต สาขา
5.17 / 5
มิฉะนั้นผลลัพธ์จะเป็นค่า rvalue หากตัวถูกดำเนินการตัวที่สองและสามไม่มีประเภทเดียวกันและมีประเภทคลาส (อาจเป็น cv ที่ผ่านการรับรอง) การแก้ปัญหาการโอเวอร์โหลดจะใช้เพื่อกำหนดการแปลง (ถ้ามี) ที่จะใช้กับตัวถูกดำเนินการ (13.3.1.2, 13.6) . หากการแก้ปัญหาโอเวอร์โหลดล้มเหลวโปรแกรมจะเกิดรูปแบบไม่ถูกต้อง มิฉะนั้นการแปลงที่กำหนดไว้จะถูกนำไปใช้และตัวถูกดำเนินการแปลงถูกนำมาใช้แทนตัวถูกดำเนินการเดิมสำหรับส่วนที่เหลือของส่วนนี้