Mengapa kelebihan operator konversi ini dipilih?

27

Pertimbangkan kode berikut .

struct any
{
    template <typename T>
    operator T &&() const;

    template <typename T>
    operator T &() const;
};
int main()
{
    int a = any{};
}

Di sini operator konversi kedua dipilih oleh resolusi kelebihan beban. Mengapa?

Sejauh yang saya mengerti, kedua operator disimpulkan operator int &&() constdan operator int &() constmasing - masing. Keduanya berada di set fungsi yang layak. Membaca [over.match.best] tidak membantu saya mencari tahu mengapa yang terakhir lebih baik.

Mengapa fungsi yang terakhir lebih baik dari yang sebelumnya?

avakar
sumber
Saya kucing yang sederhana dan saya akan mengatakan itu pasti yang kedua sekali lagi pengenalan yang lain akan menjadi perubahan yang luar biasa di C ++ 11. Itu akan menjadi standar di suatu tempat. Pertanyaan yang bagus, dapatkan jawaban positif. (Para pakar perhatian: jika komentar ini omong kosong, tolong beri tahu saya!)
Batsyeba
3
FWIW, template <typename T> operator T &&() const &&; template <typename T> operator T &() const &;mendapatkannya untuk memanggil yang pertama.
NathanOliver
5
@LightnessRaceswithMonica memungkinkan operator Konversi jika tidak, tidak akan ada banyak operator konversi.
NathanOliver
1
@Bathsheba Saya pikir itu bukan alasan mengapa. Itu seperti mengatakan bahwa memindahkan konstruktor tidak pernah dapat dipilih dengan resolusi kelebihan karena itu akan menjadi perubahan besar. Jika Anda menulis konstruktor pemindahan, Anda memilih kode Anda "rusak" oleh definisi itu.
Brian
1
@LightnessRaceswithMonica Cara saya tetap lurus di kepala saya adalah saya memperlakukan tipe pengembalian sebagai nama fungsi. Jenis yang berbeda sama dengan nama yang berbeda sama dengan kesuksesan :)
NathanOliver

Jawaban:

13

Operator konversi yang mengembalikan T&lebih disukai karena lebih khusus daripada operator konversi yang mengembalikan T&&.

Lihat C ++ 17 [temp.deduct.partial] / (3.2):

Dalam konteks panggilan ke fungsi konversi, tipe pengembalian dari templat fungsi konversi digunakan.

dan / 9:

Jika, untuk jenis tertentu, deduksi berhasil di kedua arah (yaitu, jenis identik setelah transformasi di atas) dan keduanya Pdan Amerupakan jenis referensi (sebelum diganti dengan jenis yang disebutkan di atas): - jika jenis dari templat argumen adalah referensi lvalue dan tipe dari templat parameter tidak, tipe parameter tidak dianggap paling khusus sebagai jenis argumen; ...

Brian
sumber
12

Operator konversi nilai kembalian yang disimpulkan agak aneh. Tetapi ide intinya adalah bahwa ia bertindak seperti parameter fungsi untuk memilih yang mana yang digunakan.

Dan ketika memutuskan antara T&&dan T&yang T&menang dalam aturan resolusi overload. Ini untuk mengizinkan:

template<class T>
void f( T&& ) { std::cout << "rvalue"; }
template<class T>
void f( T& ) { std::cout << "lvalue"; }

bekerja. T&&dapat cocok dengan nilai lv, tetapi ketika nilai lv dan referensi universal kelebihan tersedia, nilai l lebih disukai.

Operator konversi yang tepat mungkin:

template <typename T>
operator T&&() &&;

template <typename T>
operator T &() const; // maybe &

atau bahkan

template <typename T>
operator T() &&;

template <typename T>
operator T &() const; // maybe &

untuk mencegah perpanjangan seumur hidup yang gagal menggigit Anda.

3 Jenis yang digunakan untuk menentukan pemesanan tergantung pada konteks di mana pemesanan parsial dilakukan:

[MENGGUNTING]

(3.2) Dalam konteks panggilan ke fungsi konversi, tipe pengembalian dari templat fungsi konversi digunakan.

Yang akhirnya tergantung pada aturan "lebih khusus" ketika mengambil kelebihan:

(9.1) jika tipe dari template argumen adalah referensi lvalue dan tipe dari template parameter tidak, tipe parameter tidak dianggap paling khusus sebagai tipe argumen; jika tidak,

Dengan demikian operator T&&tidak setidaknya sama terspesialisasi operator T&, sementara tidak ada negara aturan operator T&tidak setidaknya sama terspesialisasi operator T&&, jadi operator T&lebih khusus daripada operator T&&.

Template yang lebih khusus memenangkan resolusi kelebihan lebih dari yang lebih sedikit, yang lainnya dianggap sama.

Yakk - Adam Nevraumont
sumber
Seseorang menambahkan tag pengacara bahasa saat saya menjawab; Saya hanya bisa menghapus. Saya memiliki memori yang samar-samar membaca teks yang menyatakan bahwa itu diperlakukan sebagai parameter untuk memilih yang dipanggil, dan teks yang berbicara tentang bagaimana &&vs &diperlakukan ketika memilih kelebihan template, tetapi mencari tahu teks yang tepat akan membutuhkan waktu. .
Yakk - Adam Nevraumont
4

Kami mencoba menginisialisasi intdari any. Proses untuk itu:

  1. Cari tahu semua cara kita bisa melakukan itu. Artinya, tentukan semua kandidat kita. Ini berasal dari fungsi konversi non-eksplisit yang dapat dikonversi ke intmelalui urutan konversi standar ( [over.match.conv] ). Bagian ini mengandung frasa ini:

    Panggilan ke fungsi konversi yang mengembalikan "referensi ke X" adalah glvalue tipe X, dan karenanya fungsi konversi tersebut dianggap menghasilkan Xuntuk proses pemilihan fungsi kandidat ini.

  2. Pilih kandidat terbaik.

Setelah langkah 1, kami memiliki dua kandidat. operator int&() constdan operator int&&() const, keduanya dianggap menghasilkan intuntuk tujuan pemilihan fungsi kandidat. Manakah yang menghasilkan kandidat terbaikint ?

Kami memang memiliki tiebreak yang lebih memilih referensi nilai lebih dari referensi nilai ( [over.ics.rank] /3.2.3 ). Kami tidak benar-benar mengikat referensi di sini, dan contohnya ada yang agak terbalik - ini adalah untuk kasus di mana parameternya adalah lvalue vs rvalue referensi.

Jika itu tidak berlaku, maka kita masuk ke tiebreaker [over.match.best] /2.5 dari lebih memilih templat fungsi yang lebih khusus.

Secara umum, aturan praktisnya adalah konversi yang lebih spesifik adalah yang paling cocok. Fungsi konversi referensi nilai lebih spesifik daripada fungsi konversi referensi penerusan, jadi lebih disukai. Tidak ada apa-apa tentang intkita menginisialisasi yang membutuhkan nilai (jika kita telah menginisialisasi int&&, maka operator T&() constitu tidak akan menjadi kandidat).

Barry
sumber
3.2.3 sebenarnya mengatakan T&&menang bukan? Ah, tapi kita tidak punya nilai yang terikat. Atau apakah kita? Ketika memilih kandidat kita, beberapa kata pasti telah menentukan bagaimana kita mendapatkan int&dan int&&, apakah itu mengikat?
Yakk - Adam Nevraumont
@ Yakk-AdamNevraumont Tidak, yang lebih suka referensi nilai untuk referensi nilai. Saya pikir itu mungkin bagian yang salah, dan "pemecah masalah" yang lebih khusus adalah yang benar.
Barry