Sortir tanpa pengecualian () - mengapa ia dikompilasi ketika digunakan pada std :: vector dan bukan pada std :: array, dan kompiler mana yang benar?

11

Saat memanggil std::sort()pada 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));
}

Baik gcc dan dentang mengembalikan kesalahan pada jenis di std::array- dentang kata

error: penggunaan 'sort' pengidentifikasi yang tidak dideklarasikan; maksud Anda 'std :: sort'?

Mengubah untuk std::sort(begin(foo2), end(foo2))memperbaiki masalah.

MSVC mengkompilasi kode di atas seperti yang tertulis.

Mengapa perbedaan perlakuan antara std::vectordan std::array; dan kompiler mana yang benar?

Guy Middleton
sumber
sort(...-> std::sort(.... Saya kira ADL (lookup tergantung argumen) adalah apa yang membuat Anda tersandung. Itu, atau panduan deduksi. Bagaimanapun juga; selalu memenuhi syarat fungsi yang Anda panggil.
Jesper Juhl
3
Bisa jadi perpustakaan MSVC memiliki beberapa spesialisasi std::sortyang mengarah ke pencarian bergantung pada argumen (seperti yang sudah Anda miliki untuk std::begindan std::end)?
Beberapa programmer Bung
1
@Someprogrammerdude Sederhana saja bahwa semua kontainer di stdlib VC ++ menggunakan iterator tipe kelas yang didefinisikan namespace stdbahkan di mana tipe pointer sederhana akan bekerja. Saya percaya ini adalah untuk memasukkan pemeriksaan debug-build untuk mendeteksi overruns dan kesalahan umum lainnya.
François Andrieux

Jawaban:

16

Ini datang ke jenis itu begindan endhasil untuk dan bagaimana cara kerjanya dengan Argument Dependent Lookup .

Di

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

Anda mendapatkan

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

dan karena std::vector<int>::iteratormerupakan anggota dari stdADL temuan sortdi stddan panggilan berhasil.

Dengan

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

Anda mendapatkan

sort(int*, int*)

dan karena int*bukan anggota std, ADL tidak akan melihat ke dalam stddan Anda tidak dapat menemukan std::sort.

Ini berfungsi di MSVC karena

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

menjadi

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

dan karena std::_Array_iteratormerupakan bagian dari stdpenemuan ADL sort.

Kedua kompiler benar dengan perilaku ini. std::vectordan std::arraytidak memiliki persyaratan apa pun jenis yang digunakan untuk iterator kecuali memenuhi persyaratan LegacyRandomAccessIterator dan di C ++ 17 untuk std::arrayjenis itu juga menjadi LiteralType dan di C ++ 20 bahwa itu menjadi ConstexprIterator

NathanOliver
sumber
1
Saya kira pertanyaannya adalah apakah perilaku MSVC ini adalah sesuai, yaitu apakah std::arrayiterator harus menjadi int*atau bisa menjadi jenis kelas? Demikian pula untuk std::vectoritu akan relevan dengan pertanyaan apakah iterator harus menjadi tipe kelas di mana ADL akan bekerja, atau apakah itu bisa int*juga.
walnut
@walnut Ini bisa berupa apa pun yang diinginkan implementasinya. Itu bisa berupa std::iterator, sesuatu yang lain, atau hanya sebuah pointer.
NathanOliver
1
Saya juga bertanya-tanya mengapa dalam pelaksanaan perpustakaan ini mereka memilih untuk menggunakan int*untuk std::arraytetapi tidak untuk std::vector.
François Andrieux
1
Tipe iterator untuk keduanya std::arraydan std::vectortidak ditentukan, artinya implementasi diizinkan untuk mendefinisikannya sebagai pointer mentah (kode tidak akan dikompilasi) atau pembungkus tipe kelas (kode akan dikompilasi hanya jika tipe kelas memiliki stdnamespace terkait ADL).
aschepler
1
Inilah demo di mana ADL gagal dengan alias, dan inilah demo di mana ADL berhasil dengan kelas bersarang. Baik di sini dan di tes saya sebelumnya, std::vector<T>::iteratoradalah alias.
user2357112 mendukung Monica