Saya ingin masuk ke lebih banyak meta-pemrograman template. Saya tahu bahwa SFINAE adalah singkatan dari "kegagalan substitusi bukanlah kesalahan." Tetapi dapatkah seseorang menunjukkan kepada saya penggunaan yang baik untuk SFINAE?
c++
templates
metaprogramming
sfinae
rlbond.dll
sumber
sumber
Jawaban:
Berikut salah satu contohnya ( dari sini ):
Saat
IsClassT<int>::Yes
dievaluasi, 0 tidak bisa diubahint int::*
karena int bukan kelas, jadi tidak bisa memiliki penunjuk anggota. Jika SFINAE tidak ada, maka Anda akan mendapatkan error compiler, seperti '0 tidak dapat diubah menjadi pointer anggota untuk non-class type int'. Sebaliknya, ini hanya menggunakan...
formulir yang mengembalikan Dua, dan dengan demikian mengevaluasi ke salah, int bukanlah tipe kelas.sumber
...
, melainkanint C::*
, yang belum pernah saya lihat dan harus saya cari.Saya suka menggunakan
SFINAE
untuk memeriksa kondisi boolean.Ini bisa sangat berguna. Misalnya, saya menggunakannya untuk memeriksa apakah daftar penginisialisasi yang dikumpulkan menggunakan koma operator tidak lebih dari ukuran tetap
Daftar hanya diterima jika M lebih kecil dari N, yang berarti daftar penginisialisasi tidak terlalu banyak elemen.
Sintaksnya
char(*)[C]
berarti: Pointer ke array dengan tipe elemen char dan sizeC
. JikaC
salah (0 di sini), maka kita mendapatkan tipe yang tidak validchar(*)[0]
, penunjuk ke array berukuran nol: SFINAE membuatnya sehingga template akan diabaikan kemudian.Dinyatakan dengan
boost::enable_if
, terlihat seperti iniDalam prakteknya, saya sering menemukan kemampuan untuk memeriksa kondisi sebagai kemampuan yang berguna.
sumber
M <= N ? 1 : -1
bisa berhasil.int foo[0]
. Saya tidak heran ini didukung, karena memungkinkan trik yang sangat berguna "struct diakhiri dengan 0-length array" ( gcc.gnu.org/onlinedocs/gcc/Zero-Length.html ).error C2466: cannot allocate an array of constant size 0
Dalam C ++ 11, pengujian SFINAE menjadi jauh lebih cantik. Berikut beberapa contoh penggunaan umum:
Pilih fungsi yang kelebihan beban bergantung pada sifatnya
Menggunakan apa yang disebut idiom tipe sink Anda dapat melakukan tes yang cukup sewenang-wenang pada suatu tipe seperti memeriksa apakah ia memiliki anggota dan jika anggota itu dari tipe tertentu
Berikut ini adalah contoh langsungnya: http://ideone.com/dHhyHE Saya juga baru-baru ini menulis seluruh bagian di SFINAE dan pengiriman tag di blog saya (steker tidak tahu malu tetapi relevan) http://metaporky.blogspot.de/2014/08/ bagian-7-static-dispatch-function.html
Perhatikan pada C ++ 14 ada std :: void_t yang pada dasarnya sama dengan TypeSink saya di sini.
sumber
TypeSinkT<decltype(std::declval<T&>().*(&T::bar))>
di satu tempat dan kemudianTypeSinkT<decltype(&T::bar)>
di tempat lain? Juga apakah&
perlu distd::declval<T&>
?TypeSink
, C ++ 17 memilikistd::void_t
:)Pustaka enable_if Boost menawarkan antarmuka bersih yang bagus untuk menggunakan SFINAE. Salah satu contoh penggunaan favorit saya ada di pustaka Boost.Iterator . SFINAE digunakan untuk mengaktifkan konversi jenis iterator.
sumber
C ++ 17 mungkin akan menyediakan cara umum untuk meminta fitur. Lihat N4502 untuk detailnya, tetapi sebagai contoh mandiri pertimbangkan hal berikut.
Bagian ini adalah bagian yang konstan, taruh di header.
Contoh berikut, diambil dari N4502 , menunjukkan penggunaan:
Dibandingkan dengan implementasi lainnya, yang satu ini cukup sederhana: seperangkat alat (
void_t
dandetect
) sudah cukup. Selain itu, telah dilaporkan (lihat N4502 ) bahwa ini jauh lebih efisien (waktu kompilasi dan konsumsi memori kompilator) daripada pendekatan sebelumnya.Berikut adalah contoh langsung , yang menyertakan penyesuaian portabilitas untuk GCC pra 5.1.
sumber
Berikut lain (akhir) SFINAE contoh, berdasarkan Greg Rogers 's jawabannya :
Dengan cara ini, Anda dapat memeriksa
value
nilai untuk melihat apakahT
kelas atau bukan:sumber
int C::*
dalam jawaban Anda? Bagaimana bisaC::*
menjadi nama parameter?int C::*
adalah tipe penunjuk keint
variabel anggotaC
.Berikut adalah satu artikel bagus dari SFINAE: Pengantar konsep SFINAE C ++: introspeksi waktu kompilasi anggota kelas .
Rangkumlah sebagai berikut:
declval
adalah utilitas yang memberi Anda "referensi palsu" ke objek dari jenis yang tidak dapat dibuat dengan mudah.declval
sangat berguna untuk konstruksi SFINAE kami.sumber
Di sini, saya menggunakan template function overloading (tidak secara langsung SFINAE) untuk menentukan apakah sebuah pointer adalah sebuah fungsi atau pointer kelas anggota: ( Apakah mungkin untuk memperbaiki pointer fungsi anggota iostream cout / cerr yang dicetak sebagai 1 atau benar? )
https://godbolt.org/z/c2NmzR
Cetakan
Seperti kodenya, ia bisa (tergantung pada kompiler "good" will) menghasilkan panggilan run time ke fungsi yang akan mengembalikan true atau false. Jika Anda ingin memaksa
is_function_pointer(var)
untuk mengevaluasi pada jenis kompilasi (tidak ada panggilan fungsi yang dilakukan pada waktu proses), Anda dapat menggunakanconstexpr
trik variabel:Dengan standar C ++, semua
constexpr
variabel dijamin akan dievaluasi pada waktu kompilasi ( Menghitung panjang string C pada waktu kompilasi. Apakah ini benar-benar sebuah konsteks? ).sumber
Kode berikut menggunakan SFINAE untuk membiarkan compiler memilih kelebihan beban berdasarkan apakah suatu jenis memiliki metode tertentu atau tidak:
Keluaran:
sumber