Mengapa C ++ 11 make " delete
d" fungsi berpartisipasi dalam resolusi yang berlebihan ?
Mengapa ini berguna? Atau dengan kata lain, mengapa mereka disembunyikan dan bukannya dihapus seluruhnya?
91
Mengapa C ++ 11 make " delete
d" fungsi berpartisipasi dalam resolusi yang berlebihan ?
Mengapa ini berguna? Atau dengan kata lain, mengapa mereka disembunyikan dan bukannya dihapus seluruhnya?
Jawaban:
Setengah dari tujuan
= delete
sintaks adalah untuk dapat mencegah orang memanggil fungsi tertentu dengan parameter tertentu. Ini terutama untuk mencegah konversi implisit dalam skenario tertentu. Untuk melarang kelebihan beban tertentu, itu harus berpartisipasi dalam resolusi kelebihan beban.Jawaban yang Anda kutip memberi Anda contoh sempurna:
struct onlydouble { onlydouble(std::intmax_t) = delete; onlydouble(double); };
Jika
delete
fungsi dihapus seluruhnya, itu akan membuat= delete
sintaksnya setara dengan ini:struct onlydouble2 { onlydouble2(double); };
Anda bisa melakukan ini:
onlydouble2 val(20);
Ini adalah C ++ legal. Kompilator akan melihat semua konstruktor; tidak satupun dari mereka mengambil tipe integer secara langsung. Tetapi salah satu dari mereka dapat mengambilnya setelah konversi implisit. Jadi itu akan menyebutnya.
onlydouble val(20);
Ini bukan C ++ legal. Kompilator akan melihat semua konstruktor, termasuk yang
delete
d. Ini akan melihat kecocokan persis, melaluistd::intmax_t
(yang akan sama persis dengan literal bilangan bulat apa pun). Jadi kompilator akan memilihnya dan kemudian segera mengeluarkan kesalahan, karena memilihdelete
fungsi d.= delete
berarti "Saya melarang ini," bukan hanya, "Ini tidak ada." Itu pernyataan yang jauh lebih kuat.Itu karena kita tidak memerlukan tata bahasa khusus untuk mengatakan "ini tidak ada". Kami mendapatkan ini secara implisit hanya dengan tidak menyatakan "ini" tertentu yang dimaksud. "Saya melarang ini" merupakan sebuah konstruksi yang tidak dapat dicapai tanpa tata bahasa khusus. Jadi kita mendapatkan tata bahasa khusus untuk mengatakan "Saya melarang ini" dan bukan yang lain.
Satu-satunya fungsi yang akan Anda peroleh dengan memiliki tata bahasa eksplisit "ini tidak ada" adalah mencegah seseorang untuk menyatakannya di kemudian hari. Dan itu tidak cukup berguna untuk membutuhkan tata bahasanya sendiri.
Konstruktor salinan adalah fungsi anggota khusus. Setiap kelas selalu memiliki konstruktor salinan. Sama seperti mereka selalu memiliki operator penugasan salinan, memindahkan konstruktor, dll.
Fungsi-fungsi ini ada; pertanyaannya hanyalah apakah sah untuk menelepon mereka. Jika Anda mencoba mengatakan itu
= delete
berarti mereka tidak ada, maka spesifikasi harus menjelaskan apa artinya fungsi tidak ada. Ini bukan konsep yang ditangani spesifikasi.Jika Anda mencoba memanggil fungsi yang belum dideklarasikan / didefinisikan, maka compiler akan error. Tetapi ini akan menjadi kesalahan karena pengenal yang tidak ditentukan , bukan karena kesalahan "fungsi tidak ada" (meskipun kompiler Anda melaporkannya seperti itu). Berbagai konstruktor semuanya dipanggil oleh resolusi yang berlebihan, sehingga "keberadaan" mereka ditangani dalam hal itu.
Dalam setiap kasus, ada fungsi yang dideklarasikan melalui pengenal, atau konstruktor / destruktor (juga dideklarasikan melalui pengenal, hanya pengenal tipe). Operator yang kelebihan beban menyembunyikan pengenal di balik gula sintaksis, tetapi pengenal itu masih ada.
Spesifikasi C ++ tidak dapat menangani konsep "fungsi yang tidak ada". Ini dapat menangani ketidakcocokan yang berlebihan. Itu bisa menangani ambiguitas yang berlebihan. Tapi dia tidak tahu tentang apa yang tidak ada di sana. Jadi
= delete
didefinisikan dalam istilah "upaya untuk menyebut ini gagal" yang jauh lebih berguna daripada "seolah-olah saya tidak pernah menulis baris ini" yang kurang berguna.Dan sekali lagi, baca kembali bagian pertama. Anda tidak dapat melakukannya dengan "fungsi tidak ada". Itulah alasan lain mengapa didefinisikan seperti itu: karena salah satu kasus penggunaan utama
= delete
sintaksis adalah dapat memaksa pengguna untuk menggunakan jenis parameter tertentu, untuk secara eksplisit mentransmisikan, dan sebagainya. Pada dasarnya, untuk menggagalkan konversi tipe implisit.Saran Anda tidak akan berhasil.
sumber
= delete
maksud adalah "anggota ini tidak ada", yang berarti ia tidak dapat berpartisipasi dalam resolusi yang berlebihan.= delete
berarti "anggota ini tidak ada", maka contoh pertama yang saya posting tidak akan dapat mencegah orang mengirimkan bilangan bulat keonlydouble
konstruktor , karenaonlydouble
kelebihan beban yang dihapus tidak akan ada . Itu tidak akan berpartisipasi dalam resolusi kelebihan beban, dan oleh karena itu tidak akan mencegah Anda meneruskan bilangan bulat. Yang merupakan setengah dari inti= delete
sintaks: untuk dapat mengatakan, "Anda tidak dapat meneruskan X secara implisit ke fungsi ini."=delete
? Lagi pula, kita bisa mengatakan "non-copizable" dengan melakukan hal yang persis sama: mendeklarasikan copy constructor / assignment private. Juga, perhatikan bahwa mendeklarasikan sesuatu yang privat tidak membuatnya tidak bisa salah; kode di dalam kelas masih bisa memanggilnya. Jadi tidak sama dengan= delete
. Tidak,= delete
sintaksis memungkinkan kita melakukan sesuatu yang sebelumnya sangat merepotkan dan tidak dapat dipahami dengan cara yang jauh lebih jelas dan masuk akal.Draf Kerja C ++ 2012-11-02 tidak memberikan alasan di balik aturan ini, hanya beberapa contoh
struct onlydouble { onlydouble() = delete; // OK, but redundant onlydouble(std::intmax_t) = delete; onlydouble(double); };
struct sometype { void *operator new(std::size_t) = delete; void *operator new[](std::size_t) = delete; }; sometype *p = new sometype; // error, deleted class operator new sometype *q = new sometype[3]; // error, deleted class operator new[]
struct moveonly { moveonly() = default; moveonly(const moveonly&) = delete; moveonly(moveonly&&) = default; moveonly& operator=(const moveonly&) = delete; moveonly& operator=(moveonly&&) = default; ~moveonly() = default; }; moveonly *p; moveonly q(*p); // error, deleted copy constructor
sumber