Scott Meyers memposting konten dan status buku berikutnya EC ++ 11. Dia menulis bahwa satu item dalam buku itu bisa menjadi "Hindari std::enable_if
dalam tanda tangan fungsi" .
std::enable_if
dapat digunakan sebagai argumen fungsi, sebagai tipe kembali atau sebagai templat kelas atau parameter templat fungsi untuk menghapus fungsi atau kelas secara kondisional dari resolusi kelebihan beban.
Dalam pertanyaan ini ketiga solusi ditampilkan.
Sebagai parameter fungsi:
template<typename T>
struct Check1
{
template<typename U = T>
U read(typename std::enable_if<
std::is_same<U, int>::value >::type* = 0) { return 42; }
template<typename U = T>
U read(typename std::enable_if<
std::is_same<U, double>::value >::type* = 0) { return 3.14; }
};
Sebagai parameter template:
template<typename T>
struct Check2
{
template<typename U = T, typename std::enable_if<
std::is_same<U, int>::value, int>::type = 0>
U read() { return 42; }
template<typename U = T, typename std::enable_if<
std::is_same<U, double>::value, int>::type = 0>
U read() { return 3.14; }
};
Sebagai jenis pengembalian:
template<typename T>
struct Check3
{
template<typename U = T>
typename std::enable_if<std::is_same<U, int>::value, U>::type read() {
return 42;
}
template<typename U = T>
typename std::enable_if<std::is_same<U, double>::value, U>::type read() {
return 3.14;
}
};
- Solusi mana yang lebih disukai dan mengapa saya harus menghindari yang lain?
- Dalam kasus mana "Hindari
std::enable_if
dalam tanda tangan fungsi" menyangkut penggunaan sebagai tipe pengembalian (yang bukan bagian dari tanda tangan fungsi normal tetapi spesialisasi templat)? - Apakah ada perbedaan untuk templat fungsi anggota dan non-anggota?
std::enable_if
kekacauan fungsi tanda tangan saya (terutama jelek tambahannullptr
versi fungsi argumen) karena selalu tampak seperti apa itu, hack aneh (untuk sesuatu yangstatic if
kekuatannya lakukan jauh lebih indah dan bersih) menggunakan template black-magic untuk mengeksploitasi fitur bahasa interresting. Inilah sebabnya mengapa saya lebih suka pengiriman tag bila memungkinkan (well, Anda masih memiliki argumen aneh tambahan, tetapi tidak di antarmuka publik dan juga jauh lebih jelek dan samar ).=0
ditypename std::enable_if<std::is_same<U, int>::value, int>::type = 0
capai? Saya tidak dapat menemukan sumber yang tepat untuk memahaminya. Saya tahu bagian pertama sebelum=0
memiliki tipe anggotaint
jikaU
danint
sama. Terimakasih banyak!Jawaban:
Letakkan retasan di parameter template .
Pendekatan
enable_if
pada template parameter memiliki setidaknya dua keunggulan dibandingkan yang lain:keterbacaan : penggunaan enable_if dan tipe pengembalian / argumen tidak digabung bersama menjadi satu potongan berantakan disambiguator nama ketik dan akses tipe bersarang; meskipun kekacauan disambiguator dan tipe bersarang dapat dikurangi dengan templat alias, itu masih akan menggabungkan dua hal yang tidak terkait bersama. Penggunaan enable_if terkait dengan parameter template, bukan tipe yang dikembalikan. Memiliki mereka di parameter template berarti mereka lebih dekat dengan apa yang penting;
penerapan universal : konstruktor tidak memiliki tipe pengembalian, dan beberapa operator tidak dapat memiliki argumen tambahan, sehingga tidak satu pun dari dua opsi lainnya dapat diterapkan di mana-mana. Menempatkan enable_if dalam parameter template berfungsi di mana saja karena Anda hanya dapat menggunakan SFINAE pada templat.
Bagi saya, aspek keterbacaan adalah faktor pendorong besar dalam pilihan ini.
sumber
FUNCTION_REQUIRES
makro di sini , membuatnya jauh lebih bagus untuk dibaca, dan bekerja di kompiler C ++ 03 juga, dan itu bergantung pada penggunaanenable_if
dalam tipe kembali. Selain itu, penggunaanenable_if
dalam parameter templat fungsi menyebabkan masalah untuk kelebihan beban, karena sekarang tanda tangan fungsi tidak unik yang menyebabkan kesalahan kelebihan muatan yang ambigu.enable_if
parameter templat non-tipe default, yang memungkinkan overloading. Yaituenable_if_t<condition, int> = 0
bukannyatypename = enable_if_t<condition>
.flamingdangerzone
tautan dalam komentar Anda tampaknya mengarah ke halaman pemasangan spyware sekarang. Saya menandainya untuk perhatian moderator.std::enable_if
bergantung pada " Kegagalan Substisi Bukan Kesalahan " (alias SFINAE) selama pengurangan argumen templat . Ini adalah fitur bahasa yang sangat rapuh dan Anda harus sangat berhati-hati untuk memperbaikinya.enable_if
berisi templat bersarang atau definisi tipe (petunjuk: cari::
token), maka resolusi tempatles atau tipe bersarang ini biasanya merupakan konteks yang tidak dideduksi . Kegagalan substitusi apa pun pada konteks yang tidak dideduksi adalah kesalahan .enable_if
kelebihan tidak dapat memiliki tumpang tindih karena resolusi kelebihan akan ambigu. Ini adalah sesuatu yang Anda sebagai penulis perlu periksa sendiri, meskipun Anda akan mendapatkan peringatan kompiler yang baik.enable_if
memanipulasi sekumpulan fungsi yang layak selama resolusi kelebihan beban yang dapat memiliki interaksi yang mengejutkan tergantung pada keberadaan fungsi lain yang dibawa dari lingkup lain (misalnya melalui ADL). Ini membuatnya tidak terlalu kuat.Singkatnya, ketika berhasil, ia bekerja, tetapi jika tidak, bisa sangat sulit untuk di-debug. Alternatif yang sangat baik adalah dengan menggunakan pengiriman tag , yaitu untuk mendelegasikan ke fungsi implementasi (biasanya dalam
detail
namespace atau dalam kelas pembantu) yang menerima argumen dummy berdasarkan kondisi waktu kompilasi yang sama yang Anda gunakan dienable_if
.Pengiriman tag tidak memanipulasi set overload, tetapi membantu Anda memilih fungsi yang Anda inginkan dengan memberikan argumen yang tepat melalui ekspresi waktu kompilasi (misalnya dalam sifat tipe). Dalam pengalaman saya, ini jauh lebih mudah untuk di-debug dan diperbaiki. Jika Anda adalah seorang penulis perpustakaan yang bercita-cita untuk ciri-ciri tipe canggih, Anda mungkin perlu
enable_if
entah bagaimana, tetapi untuk sebagian besar penggunaan kondisi kompilasi waktu yang teratur itu tidak dianjurkan.sumber
enable_if
memperbaikinya?is_f_able
adalah sesuatu yang saya anggap tugas untuk penulis perpustakaan yang tentu saja dapat menggunakan SFINAE ketika itu memberi mereka keuntungan, tetapi untuk pengguna "biasa" dan diberi sifatis_f_able
, saya pikir pengiriman tag lebih mudah.Parameter template
Mungkin dengan mudah digunakan salah dan menghasilkan kesalahan dengan kelebihan:
Perhatikan
typename = std::enable_if_t<cond>
bukan yang benarstd::enable_if_t<cond, int>::type = 0
jenis kembali:
Terakhir, dalam parameter fungsi:
+
,-
,*
, ...)void* = nullptr
) (jadi penunjuk fungsi akan berbeda, dan sebagainya)Ada perbedaan halus dengan warisan dan
using
:Menurut
using-declarator
(penekanan milikku):namespace.udecl
Jadi untuk argumen templat dan jenis pengembalian, metode yang disembunyikan adalah skenario berikut:
Demo (gcc salah menemukan fungsi dasar).
Sedangkan dengan argumen, skenario serupa berfungsi:
Demo
sumber