เหตุใด std :: swap จึงไม่ทำงานบนองค์ประกอบเวกเตอร์ <bool> ใน Clang / Win


14

ฉันมีรหัสเช่นนี้:

#include <vector>
#include <utility>

int main()
{
   std::vector<bool> vb{true, false};
   std::swap(vb[0], vb[1]);
}

ข้อโต้แย้งเกี่ยวกับความมีสติvector<bool>นอกเหนือจากนี้สิ่งนี้ใช้ได้ผลดีกับ:

  • เสียงดังกราวสำหรับ Mac
  • Visual Studio สำหรับ Windows
  • GCC สำหรับ Linux

จากนั้นฉันพยายามสร้างด้วย Clang บน Windows และได้รับข้อผิดพลาดต่อไปนี้ (ย่อ):

error: no matching function for call to 'swap'
                                std::swap(vb[0], vb[1]);
                                ^~~~~~~~~

note: candidate function [with _Ty = std::_Vb_reference<std::_Wrap_alloc<std::allocator<unsigned int> > >, $1 = void] not viable: expects an l-value for 1st argument
inline void swap(_Ty& _Left, _Ty& _Right) _NOEXCEPT_COND(is_nothrow_move_constructible_v<_Ty>&&

ฉันประหลาดใจที่ผลลัพธ์ต่างกันในการติดตั้งใช้งาน

ทำไมมันไม่ทำงานกับ Clang บน Windows?


ดังนั้นฉันจึงเดาว่าจำเป็นต้องมีการชี้แจงคือ: ผลลัพธ์ของoperator[]lvalue หรือไม่ และสามารถstd::swapทำงานกับ rvalues ​​และ xvalues ​​ได้หรือไม่?
Mgetz

@Metz ใช่ ไม่ในลำดับที่ คำถามนี้ถูกถามว่า "เป็นเรื่องจริง" เป็นการส่วนตัวในวันก่อนและฉันคิดว่ามันสนุกพอที่คำตอบคือ "เสียงดังกราว / วินไม่ได้หักรหัสถูกทำลายตลอดเวลานี้แต่คอมโบ Toolchain หลักไม่เคยบอกคุณ "เขียนมันที่นี่: P
Lightness Races ใน Orbit

2
เช่นเดียวกับ FYI สิ่งนี้ไม่ได้รวบรวมใน VS 2019 ที่มี/permissive-(ความสอดคล้อง) ซึ่งโดยทั่วไปควรจะใช้อยู่ดี;)
384

1
@ChrisMM แน่นอน! โหมดสอดคล้องออกเป็นส่วนหนึ่งของปริศนา (แม้ว่าเราจะไม่รู้ก่อนที่จะมองมัน!) และคำตอบของฉันก็ชี้ให้เห็นว่า: P
Lightness Races ใน Orbit

คำตอบ:


15

มาตรฐานไม่จำเป็นต้องใช้สิ่งนี้ในการรวบรวมบนtoolchain ใด ๆ !

การเรียกคืนแรกที่vector<bool>เป็นที่แปลกและ subscripting จะช่วยให้คุณวัตถุชั่วคราวของพร็อกซี่ชนิดที่เรียกว่ามากกว่าที่เกิดขึ้นจริงstd::vector<bool>::referencebool&

ข้อความแสดงข้อผิดพลาดกำลังบอกคุณว่ามันไม่สามารถผูกชั่วคราวนี้กับการconstอ้างอิงที่ไม่คุ้มค่าในการtemplate <typename T> std::swap(T& lhs, T& rhs)ใช้งานทั่วไป

ส่วนขยาย!

อย่างไรก็ตามมันกลับกลายเป็นว่า libstdc ++ กำหนดโอเวอร์โหลดสำหรับstd::swap(std::vector<bool>::reference, std::vector<bool>::reference)แต่นี่เป็นส่วนขยายของมาตรฐาน (หรือถ้าอยู่ในนั้นฉันไม่สามารถหาหลักฐานใด ๆ ได้)

libc ++ ไม่นี้เกินไป

ฉันเดาว่าการใช้ Visual Studio stdlib ที่คุณยังใช้อยู่ไม่ได้แต่หลังจากนั้นเพื่อเพิ่มการดูถูกการบาดเจ็บคุณสามารถผูกขมับเพื่ออ้างอิง lvalueใน VS (เว้นแต่ว่าคุณกำลังใช้โหมดความสอดคล้อง) ดังนั้น มาตรฐาน "ทั่วไป" std::swapฟังก์ชั่นทำงานจนกว่าคุณจะแทนที่ VS คอมไพเลอร์สำหรับคอมไพเลอร์ที่เข้มงวด Clang

ด้วยเหตุนี้คุณจึงต้องพึ่งพาส่วนขยายของทั้งสามแถบเครื่องมือที่ใช้งานได้สำหรับคุณและชุดเสียงดังกราวบน Windows เป็นเพียงสิ่งเดียวที่แสดงให้เห็นถึงการปฏิบัติตามอย่างเคร่งครัด

(ในความคิดของฉันเครื่องมือสามตัวนี้ควรได้รับการวินิจฉัยดังนั้นคุณจึงไม่ได้จัดส่งรหัสที่ไม่ใช่พกพาตลอดเวลานี้😊)

เกิดอะไรขึ้น

อาจเป็นการดึงดูดให้เพิ่มความเชี่ยวชาญของคุณเองstd::swapและstd::vector<bool>::referenceแต่คุณไม่ได้รับอนุญาตให้ทำสิ่งนี้สำหรับประเภทมาตรฐาน ที่จริงแล้วมันจะขัดแย้งกับโอเวอร์โหลดที่ libstdc ++ และ libc ++ เลือกที่จะเพิ่มเป็นส่วนขยาย

ดังนั้นที่จะพกพาและสอดคล้อง, คุณควรเปลี่ยนรหัสของคุณ

บางทีอาจเป็นเรื่องล้าสมัยที่ดี:

const bool temp = vb[0];
vb[0] = vb[1];
vb[1] = temp;

หรือใช้ประโยชน์จากฟังก์ชั่นสมาชิกคงพิเศษที่ทำสิ่งที่คุณต้องการ :

std::vector<bool>::swap(vb[0], vb[1]);

สามารถสะกดได้ดังนี้:

vb.swap(vb[0], vb[1]);

เกี่ยวกับแต่ไม่ควร AFAIK พวกเขาได้รับอนุญาตให้ทำเช่นนั้น ตราบเท่าที่พวกเขาไม่ทำลายรหัสที่สอดคล้องกันพวกเขาสามารถขยายการใช้งานเพื่อให้รหัสที่เสียหาย "ตกลง"
NathanOliver

@ NathanOliver-ReinstateMonica ดีแล้ว อย่างน้อยพวกเขาไม่ต้องวินิจฉัยการใช้สิ่งต่าง ๆ อย่างนั้นใช่ไหม? eel.is/c++draft/intro.compliance#8
Lightness Races ใน Orbit

@LightnessRaceswithMonica มีภาษาใดบ้างที่ห้ามไม่ให้มีส่วนขยายนี้
Mgetz

@Metz ขออภัยฉันไม่คุ้นเคยในทุกภาษาที่มีอยู่ดังนั้นฉันไม่สามารถตอบได้
Lightness Races ใน Orbit

ฉันไม่แน่ใจว่าใช้ส่วนขยายที่ไม่ถูกต้องตามเอกสารนี้หรือไม่ พวกเขาเพิ่มการโอเวอร์โหลดที่std::vector<bool>::referenceทำให้ไม่มีอะไรเกิดขึ้นจริง สำหรับฉันแล้วดูเหมือนว่าการใช้สิ่งที่ต้องการchar * foo = "bar";จะต้องได้รับการวินิจฉัยเนื่องจากมีรูปแบบไม่ดี
NathanOliver
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.