Unqualified sort () - tại sao nó biên dịch khi được sử dụng trên std :: vector mà không phải trên std :: mảng, và trình biên dịch nào là đúng?


11

Khi gọi std::sort()trên 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));
}

Cả gcc và clang đều trả về lỗi trên sắp xếp trên std::array- clang nói

lỗi: sử dụng định danh không khai báo 'sort'; ý bạn là 'std :: sort'?

Thay đổi để std::sort(begin(foo2), end(foo2))khắc phục vấn đề.

MSVC biên dịch mã ở trên như văn bản.

Tại sao sự khác biệt trong điều trị giữa std::vectorstd::array; và trình biên dịch nào là đúng?


sort(...-> std::sort(.... Tôi đoán rằng ADL (tra cứu phụ thuộc đối số) là thứ khiến bạn vấp ngã. Đó, hoặc hướng dẫn khấu trừ. Trong bất kỳ trường hợp nào; luôn luôn đủ điều kiện các chức năng bạn gọi.
Jesper Juhl

3
Có thể là thư viện MSVC có một số chuyên môn hóa std::sortdẫn đến tra cứu phụ thuộc vào đối số (như bạn đã có std::beginstd::end)?
Một số lập trình viên anh chàng

1
@Someprogrammerdude Đơn giản là tất cả các container trong stdlib của VC ++ đều sử dụng các trình vòng lặp loại lớp được xác định namespace stdngay cả khi một loại con trỏ đơn giản sẽ hoạt động. Tôi tin rằng điều này là để chèn kiểm tra gỡ lỗi để phát hiện lỗi tràn và các lỗi phổ biến khác.
François Andrieux

Câu trả lời:


16

Điều này thuộc về loại beginendkết quả và cách thức hoạt động với Tra cứu phụ thuộc đối số .

Trong

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

bạn lấy

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

và kể từ khi std::vector<int>::iteratorlà thành viên của stdADL phát hiện sorttại stdvà cuộc gọi thành công.

Với

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

Bạn lấy

sort(int*, int*)

và vì int*không phải là thành viên của std, ADL sẽ không xem xét stdvà bạn không thể tìm thấy std::sort.

Điều này hoạt động trong MSVC vì

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

trở thành

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

và vì std::_Array_iteratorlà một phần của stdADL tìm thấy sort.

Cả hai trình biên dịch đều đúng với hành vi này. std::vectorstd::arraykhông có bất kỳ yêu cầu nào về loại được sử dụng cho iterator ngoại trừ việc nó đáp ứng yêu cầu LegacyRandomAccessIterator và trong C ++ 17 std::array, loại đó cũng là một loại chữ và trong C ++ 20, nó là một ConstexprIterator


1
Tôi đoán câu hỏi là liệu hành vi của MSVC có phù hợp hay không, tức là std::arrayiterator phảiint*hoặc nó có thể là một loại lớp không? Tương tự như vậy đối với std::vectorcâu hỏi liệu iterator có phải là một loại lớp mà ADL sẽ hoạt động không, hoặc liệu nó có thể int*như vậy không.
quả óc chó

@walnut Nó có thể là bất cứ điều gì việc thực hiện muốn nó được. Nó có thể là một std::iteratorcái gì đó khác, hoặc chỉ là một con trỏ.
NathanOliver

1
Tôi cũng tự hỏi tại sao trong thư viện này họ chọn sử dụng int*cho std::arraynhưng không phải cho std::vector.
François Andrieux

1
Các kiểu trình lặp cho cả hai std::arraystd::vectorkhông được chỉ định, có nghĩa là việc triển khai được phép định nghĩa chúng là các con trỏ thô (mã sẽ không biên dịch) hoặc các hàm bao kiểu lớp (mã sẽ chỉ biên dịch nếu loại lớp có stdkhông gian tên liên quan đến ADL).
aschepler

1
Đây là bản demo trong đó ADL thất bại với bí danh và đây là bản demo trong đó ADL thành công với lớp lồng nhau. Cả ở đây và trong các thử nghiệm trước đây của tôi, std::vector<T>::iteratorlà một bí danh.
user2357112 hỗ trợ Monica
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.