มาตรฐานมีการเปลี่ยนแปลงตั้งแต่คำถาม (และคำตอบส่วนใหญ่) ถูกโพสต์ในการแก้ปัญหาของรายงานข้อบกพร่องนี้
วิธีที่จะทำให้for(:)
ลูปทำงานกับประเภทของคุณX
ได้แล้วตอนนี้หนึ่งในสองวิธี:
และคล้ายกันสำหรับconst
รูปแบบต่างๆ สิ่งนี้จะทำงานทั้งในคอมไพเลอร์ที่ใช้การเปลี่ยนแปลงรายงานข้อบกพร่องและคอมไพเลอร์ที่ไม่มี
วัตถุที่ส่งคืนไม่จำเป็นต้องเป็นตัววนซ้ำจริง ๆ การfor(:)
วนซ้ำซึ่งแตกต่างจากส่วนใหญ่ของมาตรฐาน C ++ ถูกระบุให้ขยายเป็นสิ่งที่เทียบเท่ากับ :
for( range_declaration : range_expression )
กลายเป็น:
{
auto && __range = range_expression ;
for (auto __begin = begin_expr,
__end = end_expr;
__begin != __end; ++__begin) {
range_declaration = *__begin;
loop_statement
}
}
โดยที่ตัวแปรที่ขึ้นต้นด้วย__
มีไว้สำหรับการแสดงออกเท่านั้นและbegin_expr
และend_expr
เป็นเวทย์มนตร์ที่เรียกใช้begin
/ end
.²
ข้อกำหนดเกี่ยวกับค่าส่งคืนเริ่มต้น / สิ้นสุดนั้นง่าย: คุณต้องโอเวอร์โหลดล่วงหน้า - ++
ตรวจสอบให้แน่ใจว่านิพจน์การเริ่มต้นนั้นถูกต้องไบนารี!=
ที่สามารถใช้ในบริบทบูลีน, ยูนารี*
ที่ส่งคืนสิ่งที่คุณสามารถกำหนดค่าเริ่มต้นrange_declaration
ด้วย destructor
การทำเช่นนี้ในลักษณะที่ไม่เข้ากันได้กับตัววนซ้ำอาจเป็นความคิดที่ไม่ถูกต้องเนื่องจากการทำซ้ำในอนาคตของ C ++ อาจเป็นนักขี่ม้าที่ค่อนข้างจะทำลายรหัสของคุณหากคุณทำ
นอกจากนี้ยังมีเหตุผลที่การแก้ไขมาตรฐานในอนาคตจะอนุญาตend_expr
ให้ส่งคืนประเภทที่แตกต่างกันbegin_expr
ได้ สิ่งนี้มีประโยชน์ในการอนุญาตให้ประเมิน "lazy-end" (เช่นการตรวจจับการสิ้นสุดค่า null) ซึ่งง่ายต่อการปรับให้มีประสิทธิภาพเท่ากับการวนรอบ C ที่เขียนด้วยมือและข้อดีอื่น ๆ ที่คล้ายกัน
¹โปรดทราบว่าfor(:)
ลูปจะเก็บชั่วคราวในauto&&
ตัวแปรและส่งให้คุณในรูปแบบ lvalue คุณไม่สามารถตรวจพบว่าคุณทำซ้ำชั่วคราว (หรือ rvalue อื่น ๆ ); โอเวอร์โหลดดังกล่าวจะไม่ถูกเรียกโดยfor(:)
ลูป ดู [stmt.ranged] 1.2-1.3 จาก n4527
²ทั้งโทรbegin
/ end
วิธีการหรือ ADL เท่านั้นค้นหาแบบของฟังก์ชั่นฟรีbegin
/ end
, หรือมายากลสำหรับการสนับสนุนอาร์เรย์แบบ C โปรดทราบstd::begin
ว่าไม่ได้เรียกว่าเว้นแต่จะrange_expression
ส่งกลับวัตถุประเภทnamespace std
หรือขึ้นอยู่กับเดียวกัน
ใน C ++ 17 มีการอัปเดตนิพจน์ช่วงสำหรับ
{
auto && __range = range_expression ;
auto __begin = begin_expr;
auto __end = end_expr;
for (;__begin != __end; ++__begin) {
range_declaration = *__begin;
loop_statement
}
}
ด้วยประเภทของ__begin
และ__end
ได้รับการแยกออก
สิ่งนี้อนุญาตให้ตัววนซ้ำสิ้นสุดไม่เหมือนกับชนิดเริ่มต้น ประเภทตัววนซ้ำสุดท้ายของคุณสามารถเป็น "sentinel" ซึ่งรองรับเฉพาะ!=
กับตัววนซ้ำเริ่มต้นเท่านั้น
ตัวอย่างที่ใช้งานได้จริงว่าทำไมสิ่งนี้มีประโยชน์คือตัววนซ้ำสุดท้ายของคุณสามารถอ่าน "ตรวจสอบchar*
เพื่อดูว่ามันชี้ไปที่'0'
" เมื่อ==
ใช้ a char*
หรือไม่ สิ่งนี้อนุญาตให้มีการแสดงออกในช่วง C ++ เพื่อสร้างรหัสที่ดีที่สุดเมื่อทำการวนซ้ำผ่านchar*
บัฟเฟอร์ที่สิ้นสุดด้วยค่า null
struct null_sentinal_t {
template<class Rhs,
std::enable_if_t<!std::is_same<Rhs, null_sentinal_t>{},int> =0
>
friend bool operator==(Rhs const& ptr, null_sentinal_t) {
return !*ptr;
}
template<class Rhs,
std::enable_if_t<!std::is_same<Rhs, null_sentinal_t>{},int> =0
>
friend bool operator!=(Rhs const& ptr, null_sentinal_t) {
return !(ptr==null_sentinal_t{});
}
template<class Lhs,
std::enable_if_t<!std::is_same<Lhs, null_sentinal_t>{},int> =0
>
friend bool operator==(null_sentinal_t, Lhs const& ptr) {
return !*ptr;
}
template<class Lhs,
std::enable_if_t<!std::is_same<Lhs, null_sentinal_t>{},int> =0
>
friend bool operator!=(null_sentinal_t, Lhs const& ptr) {
return !(null_sentinal_t{}==ptr);
}
friend bool operator==(null_sentinal_t, null_sentinal_t) {
return true;
}
friend bool operator!=(null_sentinal_t, null_sentinal_t) {
return false;
}
};
ตัวอย่างสดในคอมไพเลอร์โดยไม่มีการสนับสนุนแบบเต็ม C ++ 17; for
ขยายวงด้วยตนเอง
begin/end
begin/end
เพียงแค่ระวังให้เนมสเปซที่คุณใส่ฟังก์ชั่นฟรี: stackoverflow.com/questions/28242073/…