Cara membandingkan dua urutan konversi standar menggunakan peringkat konversi yang terkandung
#include <iostream>
void g(int*); //#1
void g(int (&arr)[2]); //#2
void f(int*); //#3
void f(int const*); //#4
int main(){
int arr[2] ={0};
f(arr); // choose #3
g(arr); //ambiguous
}
Perhatikan kode di atas, # 3 dipilih f(ptr)
, namun g(arr)
memberikan ambiguous
diagnostik.
Aturan untuk memilih fungsi terbaik didefinisikan sebagai:
Urutan konversi standar S1 adalah urutan konversi yang lebih baik daripada urutan konversi standar S2 jika
- S1 adalah urutan S2 yang tepat (membandingkan urutan konversi dalam bentuk kanonik yang didefinisikan oleh [over.ics.scs], tidak termasuk Transformasi Nilai L; urutan konversi identitas dianggap sebagai penerusan dari urutan konversi non-identitas ) atau , jika bukan itu
Jadi lihatlah over.ics.scs # 3
Ini digunakan untuk menentukan peringkat urutan konversi standar. Peringkat urutan konversi ditentukan dengan mempertimbangkan peringkat setiap konversi dalam urutan dan peringkat dari setiap pengikatan referensi.
Menurut pemahaman saya tentang aturan di atas, saya dapat memahami mengapa #3
overload terbaik f(ptr)
, yaitu:
Diberikan S1 sebagai (arr => int *):
Array-to-pointer conversion -> (identity conversion)
^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^
int[2] => int* int* => int*
sementara diberikan S2 sebagai (ptr => int const *)
Array-to-pointer conversion -> Qualification conversions -> identity conversion
^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^
int[2] => int* int* => int const* int const* => int const*
Karena identity conversion
merupakan kelulusan yang layak Qualification conversions
, maka S1 lebih baik dari S2. Jadi, # 3 dipilih dengan resolusi kelebihan beban untuk f(ptr)
.
Ketika saya menggunakan proses serupa untuk menentukan mana yang terbaik g(arr)
, saya mengalami masalah.
Sekali lagi, diberikan S1 sebagai (arr => int *)
Array-to-pointer conversion -> identity conversion
^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^
int[2] => int* int* => int*
sementara diberikan S2 sebagai (arr => int (& arr) [2])
Ketika parameter tipe referensi mengikat langsung ke ekspresi argumen, urutan konversi implisit adalah konversi identitas, kecuali ekspresi argumen memiliki tipe yang merupakan kelas turunan dari tipe parameter, dalam hal ini urutan konversi implisit adalah turunan- Konversi ke basis
identity conversion
^^^^^^^^^^^^^^^^^^^
bind to reference
Di sini, identity conversion
of S2
adalah urutan yang tepat Array-to-pointer conversion
dari S1
, maka itu harus lebih baik daripada S1
, mengapa compiler yang mengeluh g(arr)
adalah permintaan yang ambigu?
Apakah saya salah membaca tentang cara menentukan peringkat urutan konversi standar? Bagaimana membandingkan dua ICS standar (peringkat konversi yang terkandung)?
Jawaban
Poin utamanya ada di sini:
S1 adalah urutan S2 yang tepat (membandingkan urutan konversi dalam bentuk kanonik yang didefinisikan oleh [over.ics.scs], tidak termasuk Transformasi Nilai L ; urutan konversi identitas dianggap sebagai penerusan dari urutan konversi non-identitas) atau , jika bukan itu
Artinya, untuk pemanggilan fungsi g(arr)
, semua konversi Array-to-pointer tidak digunakan untuk menentukan rank. Dengan kata lain, dari tipe int[2]
ke tipe int*
, hanya ada konversi identitas yang digunakan untuk menentukan peringkat. Oleh karena itu, S1 dari void g(int*);
dan S2 void g(int (&arr)[2]);
adalah ICS yang tidak dapat dibedakan, sehingga penyusun memberikan kesalahan yang ambigu.
Sebaliknya, konversi untuk void f(int*);
dan void f(int const*);
digunakan untuk membandingkan peringkat masing-masing adalah identity conversion
dan qualification conversion
.
Menurut aturan:
urutan konversi identitas dianggap sebagai kelanjutan dari setiap urutan konversi non-identitas
Oleh karena itu, Qualification conversion
dianggap memiliki peringkat yang lebih buruk dari pada identity conversion
. Jadi, void f(int*)
memenangkan persaingan.
Anda mencoba menerapkan over.ics.rank-3.2.1 ke kumpulan kelebihan beban ini, tetapi aturan ini tidak berlaku untuk f
atau g
.
Mengingat panggilan tersebut f(arr);
, saat menjalankan resolusi kelebihan beban untuk f
, kedua beban berlebih memerlukan urutan konversi standar yang terdiri dari konversi Array-ke-penunjuk , dan keduanya memiliki peringkat yang sama, yaitu Pencocokan Tepat . Pemutus dasi yang digunakan dalam kasus ini adalah over.match.best # over.ics.rank-3.2.5 :
Urutan konversi standar S1 adalah urutan konversi yang lebih baik daripada urutan konversi standar S2 jika
...
S1 dan S2 hanya berbeda dalam konversi kualifikasi mereka ([kualitas konv.]) Dan menghasilkan tipe serupa T1 dan T2, di mana T1 dapat dikonversi ke T2 dengan konversi kualifikasi.
Ada contoh mengikuti aturan ini yang menunjukkan cara kerja aturan.
Untuk kumpulan kelebihan beban f
, T1
is int *
dan T2
is int const *
, dan T1
dapat dikonversi menjadi T2
dengan konversi kualifikasi.
Dalam kasus panggilan g(arr);
, saat melakukan resolusi kelebihan beban, kelebihan beban g(int (&)[2])
diberi peringkat sebagai pencocokan Tepat , karena urutan konversi standar yang diperlukan adalah Tidak Perlu Konversi .
Namun, kelebihan beban g(int*)
juga diberi peringkat sebagai pencocokan Tepat , karena urutan konversi standar yang diperlukan adalah konversi Array-to-Pointer .
Tidak seperti untuk f
, tidak ada aturan di [over.ics.rank] yang memisahkan antara urutan konversi standar untuk g
, dan panggilan gagal.