D: เหตุใด opIndex จึงไม่ผ่านการรับรองในคลาส std.container.Array

ฉันเพิ่งต้องการใช้ std.container.Array และดำเนินการสร้างคลาสที่มีฟังก์ชันสมาชิก getter ซึ่งส่งคืนค่าจากคลาส Array ฉันรู้ได้อย่างรวดเร็วว่าฉันไม่สามารถกำหนดคุณสมบัติ getter ของฉันได้ เนื่องจาก opIndex เป็นฟังก์ชันที่ไม่แน่นอน

ฉันพยายามเปลี่ยนซอร์สโค้ดเพื่อให้มีคุณสมบัติ Array.opIndex และมันก็ใช้งานได้ดี อย่างไรก็ตาม การทดสอบหน่วยบางอย่างใน std.algorithm ไม่ผ่าน โดยบ่นว่าค่าที่ส่งคืนของ Array.opIndex ไม่ใช่ค่า lvalue

นี่คือโค้ดสำหรับ Array.opIndex:

ref T opIndex(size_t i)
{
    version (assert) if (!_data.refCountedStore.isInitialized) throw new RangeError();
    return _data._payload[i];
}

มีบางอย่างที่ฉันขาดหายไปที่นี่หรือไม่? เหตุใดจึงไม่ผ่านการรับรอง?


person David Eränen    schedule 18.08.2014    source แหล่งที่มา


คำตอบ (1)


มีปัญหาหลายประการในการทำให้คอนเทนเนอร์ถูกต้อง const เนื่องจาก const ทำให้คอนเทนเนอร์ไม่สามารถเปลี่ยนแปลงสิ่งใดภายในได้ ไม่เหมือนใน C++ ซึ่งคุณสามารถสร้างบางสิ่งได้ mutable ตราบเท่าที่ ในขณะที่คุณแน่ใจว่าฟังก์ชันต่างๆ นั้นมีเหตุผล const IIRC มีการดำเนินการที่ Array ทำซึ่งในทางทฤษฎีอาจเป็น const แต่ไม่สามารถเกิดขึ้นได้เนื่องจากวิธีการทำงานของภายในบางส่วน และฉันจะไม่แปลกใจเลยถ้าด้วยเหตุนี้ คนที่ทำงานด้านนี้จึงไม่ได้ทำสิ่งใดเลย const แม้ว่าบางส่วนอาจเป็นก็ตาม

สำหรับ opIndex ฉันไม่เห็นสิ่งใดที่ชัดเจนในการใช้งานนั้นซึ่งไม่สามารถเป็น const ได้ และความจริงที่ว่ามันคอมไพล์เลยก็บอกเป็นนัยว่ามันอาจใช้งานได้ อย่างไรก็ตาม หากคุณทำเช่นนั้น คุณจะต้องโอเวอร์โหลดมันแทนที่จะทำให้โอเวอร์โหลดนั้น const ไม่เช่นนั้นคุณจะไม่สามารถกำหนดให้กับมันได้ - ซึ่งน่าจะเป็นสิ่งที่ std.algorithm บ่นเกี่ยวกับมัน ดังนั้นคุณต้องมีบางอย่างเช่น

ref T opIndex(size_t i) {...}
ref const(T) opIndex(size_t i) const {...}

เพื่อให้ยังคงสามารถมอบหมายงานให้กับมันได้ - เช่น arr[5] = "foo"; - ตราบใดที่ Array ไม่ใช่ const อย่างไรก็ตาม เนื่องจากการดำเนินการหลายอย่างของ Array ไม่สามารถเป็น const ได้เนื่องจากวิธีการใช้งาน ฉันจึงไม่รู้ว่าการสร้างฟังก์ชันอย่างเช่น opIndex const นั้นมีประโยชน์เพียงใด เนื่องจากคุณจะถูกจำกัดอย่างมากในสิ่งที่คุณสามารถทำได้ด้วย const Array!T แม้ว่าทุกฟังก์ชันของสมาชิกที่สามารถเป็น const ได้จะเป็น const

person Jonathan M Davis    schedule 18.08.2014
comment
ขอบคุณสำหรับคำตอบโจนาธาน! - person David Eränen; 19.08.2014
comment
คุณถูกต้องว่าฉันไม่สามารถเปลี่ยนโอเวอร์โหลดดั้งเดิมเป็น const ได้ แต่ฉันต้องเพิ่มอีกอันหนึ่ง คุณถูกต้องด้วยว่าจำเป็นต้องส่งคืนการอ้างอิง const(T) และไม่ใช่การอ้างอิง T การทดสอบหน่วยยังคงใช้งานได้กับการเปลี่ยนแปลงนี้! บางทีควรเพิ่มเวอร์ชัน const นี้ลงในโค้ด - person David Eränen; 19.08.2014
comment
และเพียงเพื่อชี้แจง: ฉันไม่ต้องการให้ opIndex เป็น const เพื่อให้สามารถใช้กับ const Array!T; แต่ฉันต้องการที่จะ const-qualify ฟังก์ชั่นสมาชิก getter ของฉันซึ่งใช้ Array.opIndex เป็นแบบอ่านอย่างเดียวแทน - person David Eränen; 19.08.2014
comment
@DavidEränen คุณกำลังใช้ const Array!T หากคุณใช้ opIndex ภายในฟังก์ชัน const ของ struct หรือคลาสที่เป็นสมาชิกอยู่ แต่ถ้าสิ่งที่คุณพยายามทำคือใช้ opIndex แทนที่จะใช้เป็น const ใน โดยรวมก็ดูเหมือนว่าจะสามารถใช้งานได้อย่างง่ายดาย อย่าลังเลที่จะเปิดคำขอการปรับปรุง issues.dlang.org หรือแม้แต่สร้างคำขอดึงข้อมูลหากคุณ รู้สึกกล้าหาญ github.com/D-Programming-Language/phobos ดูเหมือนว่าควรจะทำงานมากกว่านี้ในการทำให้ Array const-correct แม้ว่าเราจะไม่สามารถทำให้มันถูกต้องได้อย่างสมบูรณ์ก็ตาม - person Jonathan M Davis; 19.08.2014