Unqualified sort () - ทำไมมันรวบรวมเมื่อใช้กับ std :: vector และไม่ได้อยู่ในอาร์เรย์ std :: และคอมไพเลอร์ใดที่ถูกต้อง?


11

เมื่อโทรstd::sort()บนstd::array:

#include <vector>
#include <array>
#include <algorithm>

int main() {
    std::vector<int> foo{4, 1, 2, 3};
    sort(begin(foo), end(foo));

    std::array<int, 4> foo2{4, 1, 2, 3};
    sort(begin(foo2), end(foo2));
}

ทั้ง gcc และ clang ส่งคืนข้อผิดพลาดในการเรียงลำดับบนstd::array- clang กล่าว

ข้อผิดพลาด: การใช้ตัวระบุที่ไม่ได้ประกาศ 'sort'; หมายถึง 'std :: sort' หรือเปล่า

การเปลี่ยนเป็นการstd::sort(begin(foo2), end(foo2))แก้ไขปัญหา

MSVC รวบรวมรหัสข้างต้นตามที่เขียนไว้

ทำไมความแตกต่างในการรักษาระหว่างstd::vectorและstd::array; และคอมไพเลอร์ตัวใดที่ถูกต้อง?


sort(...std::sort(...-> ฉันเดาว่า ADL (การค้นหาการโต้แย้งขึ้นอยู่กับ) เป็นสิ่งที่สะดุดคุณ นั่นหรือคำแนะนำการหักเงิน ไม่ว่ากรณีใด ๆ; มักจะมีคุณสมบัติฟังก์ชั่นที่คุณโทร
Jesper Juhl

3
อาจเป็นไปได้ว่าไลบรารี MSVC มีความเชี่ยวชาญเฉพาะด้านstd::sortที่นำไปสู่การค้นหาแบบอิงอาร์กิวเมนต์ (เช่นที่คุณมีอยู่แล้วstd::beginและstd::end)?
โปรแกรมเมอร์บางคนเพื่อน

1
@Someprogrammerdude เป็นเพียงแค่ว่าคอนเทนเนอร์ทั้งหมดใน stdlib ของ VC ++ ใช้ตัวทำซ้ำชนิดคลาสที่กำหนดไว้namespace stdแม้ในที่ที่ตัวชี้แบบธรรมดาจะทำงานได้ ฉันเชื่อว่านี่คือการแทรกการตรวจแก้จุดบกพร่องสร้างเพื่อตรวจสอบการบุกรุกและข้อผิดพลาดทั่วไปอื่น ๆ
François Andrieux

คำตอบ:


16

สิ่งนี้เกิดขึ้นได้กับประเภทที่beginและendผลลัพธ์และวิธีการทำงานกับการค้นหาที่ขึ้นอยู่กับอาร์กิวเมนต์

ใน

sort(begin(foo), end(foo));

คุณได้รับ

sort(std::vector<int>::iterator, std::vector<int>::iterator)

และตั้งแต่std::vector<int>::iteratorเป็นสมาชิกของstdพบ ADL sortในstdและโทรประสบความสำเร็จ

กับ

sort(begin(foo2), end(foo2));

คุณได้รับ

sort(int*, int*)

และเนื่องจากint*ไม่ใช่สมาชิกstdADL จะไม่ดูstdและคุณไม่สามารถค้นหาstd::sortได้

สิ่งนี้ใช้ได้ใน MSVC เพราะ

sort(begin(foo2), end(foo2));

กลายเป็น

sort(std::_Array_iterator, std::_Array_iterator)

และเนื่องจากstd::_Array_iteratorเป็นส่วนหนึ่งของพบ std ADLsort

คอมไพเลอร์ทั้งสองนั้นถูกต้องกับพฤติกรรมนี้ std::vectorและstd::arrayไม่มีข้อกำหนดใด ๆ เกี่ยวกับประเภทที่ใช้สำหรับตัววนซ้ำยกเว้นว่าเป็นไปตามข้อกำหนดของLegacyRandomAccessIteratorและใน C ++ 17 สำหรับstd::arrayประเภทนั้นก็จะเป็นประเภทของตัวอักษรและใน C ++ 20 ที่เป็นConstexprIterator


1
ฉันเดาว่าคำถามคือพฤติกรรมของ MSVC สอดคล้องหรือไม่เช่นตัวstd::arrayวนซ้ำต้องเป็นint*หรือเป็นประเภทของคลาสหรือไม่ ในทำนองเดียวกันstd::vectorมันจะเกี่ยวข้องกับคำถามว่าตัววนซ้ำต้องเป็นประเภทคลาสที่ ADL ใช้งานได้หรือไม่หรืออาจint*เป็นเช่นนั้นก็ได้
walnut

@ วอลนัทมันสามารถเป็นสิ่งที่การดำเนินการต้องการให้เป็น อาจเป็นstd::iteratorอย่างอื่นหรือเพียงแค่ตัวชี้
NathanOliver

1
ฉันยังสงสัยว่าทำไมในการดำเนินงานห้องสมุดนี้พวกเขาเลือกที่จะใช้int*สำหรับการแต่ไม่ได้สำหรับstd::array std::vector
François Andrieux

1
ประเภท iterator สำหรับทั้งสองstd::arrayและstd::vectorมีที่ไม่ได้ระบุความหมายของการดำเนินการได้รับอนุญาตให้กำหนดให้เป็นตัวชี้ดิบ (รหัสจะไม่รวบรวม) หรือระดับชนิดห่อ (รหัสจะรวบรวมเฉพาะในกรณีที่ประเภทชั้นมีstdเป็น ADL เกี่ยวข้อง namespace)
aschepler

1
นี่คือตัวอย่างที่ ADL ล้มเหลวด้วยนามแฝงและนี่คือตัวอย่างที่ ADL ประสบความสำเร็จกับคลาสที่ซ้อนกัน ทั้งที่นี่และในการทดสอบก่อนหน้าของฉันstd::vector<T>::iteratorเป็นนามแฝง
user2357112 รองรับ Monica
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.