enable_if
Kelas
Secara kondisional membuat instans jenis untuk resolusi kelebihan beban SFINAE. Typedef enable_if<Condition,Type>::type
berlapis ada—dan merupakan sinonim untuk Type
—jika dan hanya jika Condition
adalah true
.
Sintaks
template <bool B, class T = void>
struct enable_if;
Parameter
B
Nilai yang menentukan keberadaan jenis yang dihasilkan.
T
Jenis untuk membuat instans jika B
adalah true
.
Keterangan
Jika B
adalah true
, enable_if<B, T>
memiliki typedef berlapis bernama "type" yang merupakan sinonim untuk T
.
Jika B
adalah false
, enable_if<B, T>
tidak memiliki typedef berlapis bernama "type".
Templat alias ini disediakan:
template <bool B, class T = void>
using enable_if_t = typename enable_if<B,T>::type;
Di C++, kegagalan penggantian parameter templat bukan kesalahan dalam dirinya sendiri—ini disebut sebagai SFINAE (kegagalan penggantian bukan kesalahan). Biasanya, enable_if
digunakan untuk menghapus kandidat dari resolusi kelebihan beban—yaitu, memusnahkan set kelebihan beban—sehingga satu definisi dapat ditolak demi definisi lain. Ini sesuai dengan perilaku SFINAE. Untuk informasi selengkapnya tentang SFINAE, lihat Kegagalan penggantian bukanlah kesalahan di Wikipedia.
Berikut adalah empat contoh skenario:
- Skenario 1: Membungkus jenis pengembalian fungsi:
template <your_stuff>
typename enable_if<your_condition, your_return_type>::type
yourfunction(args) {// ...
}
// The alias template makes it more concise:
template <your_stuff>
enable_if_t<your_condition, your_return_type>
yourfunction(args) {// ...
}
- Skenario 2: Menambahkan parameter fungsi yang memiliki argumen default:
template <your_stuff>
your_return_type_if_present
yourfunction(args, enable_if_t<your condition, FOO> = BAR) {// ...
}
- Skenario 3: Menambahkan parameter templat yang memiliki argumen default:
template <your_stuff, typename Dummy = enable_if_t<your_condition>>
rest_of_function_declaration_goes_here
- Skenario 4: Jika fungsi Anda memiliki argumen non-templat, Anda dapat membungkus jenisnya:
template <typename T>
void your_function(const T& t,
enable_if_t<is_something<T>::value, const string&>
s) {// ...
}
Skenario 1 tidak berfungsi dengan konstruktor dan operator konversi karena mereka tidak memiliki jenis pengembalian.
Skenario 2 membuat parameter tidak disebutkan namanya. Anda dapat mengatakan ::type Dummy = BAR
, tetapi namanya Dummy
tidak relevan, dan memberinya nama kemungkinan akan memicu peringatan "parameter yang tidak direferensikan". Anda harus memilih FOO
jenis parameter fungsi dan BAR
argumen default. Anda dapat mengatakan int
dan 0
, tetapi kemudian pengguna kode Anda secara tidak sengaja dapat meneruskan ke fungsi bilangan bulat tambahan yang akan diabaikan. Sebagai gantinya, kami sarankan Anda menggunakan void **
dan 0
atau nullptr
karena hampir tidak ada yang dapat dikonversi ke void **
:
template <your_stuff>
your_return_type_if_present
yourfunction(args, typename enable_if<your_condition, void **>::type = nullptr) {// ...
}
Skenario 2 juga berfungsi untuk konstruktor biasa. Namun, ini tidak berfungsi untuk operator konversi karena mereka tidak dapat mengambil parameter tambahan. Ini juga tidak berfungsi untuk variadic
konstruktor karena menambahkan parameter tambahan membuat parameter fungsi mengemas konteks yang tidak disimpulkan dan dengan demikian mengalahkan tujuan .enable_if
Skenario 3 menggunakan nama Dummy
, tetapi bersifat opsional. Hanya " typename = typename
akan berfungsi, tetapi jika Anda berpikir itu terlihat aneh, Anda dapat menggunakan nama "dummy"—hanya jangan gunakan nama yang mungkin juga digunakan dalam definisi fungsi. Jika Anda tidak memberikan jenis ke enable_if
, itu default untuk membatalkan, dan itu sangat masuk akal karena Anda tidak peduli apa itu Dummy
. Ini berfungsi untuk semuanya, termasuk operator konversi dan variadic
konstruktor.
Skenario 4 berfungsi di konstruktor yang tidak memiliki jenis pengembalian, dan dengan demikian memecahkan batasan pembungkusan Skenario 1. Namun, Skenario 4 terbatas pada argumen fungsi non-templat, yang tidak selalu tersedia. (Menggunakan Skenario 4 pada argumen fungsi templat mencegah pengurangan argumen templat untuk mengerjakannya.)
enable_if
sangat kuat, tetapi juga berbahaya jika disalahgunakan. Karena tujuannya adalah untuk membuat kandidat lenyap sebelum resolusi kelebihan beban, ketika disalahgunakan, efeknya bisa sangat membingungkan. Berikut beberapa rekomendasi kami:
Jangan gunakan
enable_if
untuk memilih antara implementasi pada waktu kompilasi. Jangan pernah menulis satuenable_if
untukCONDITION
dan yang lain untuk!CONDITION
. Sebagai gantinya, gunakan pola pengiriman tag—misalnya, algoritma yang memilih implementasi tergantung pada kekuatan iterator yang diberikan.Jangan gunakan
enable_if
untuk menegakkan persyaratan. Jika Anda ingin memvalidasi parameter templat, dan jika validasi gagal, menyebabkan kesalahan alih-alih memilih implementasi lain, gunakanstatic_assert
.Gunakan
enable_if
saat Anda memiliki set kelebihan beban yang membuat kode yang baik ambigu. Paling sering, ini terjadi secara implisit mengonversi konstruktor.
Contoh
Contoh ini menjelaskan bagaimana fungsi std::make_pair()
templat Pustaka Standar C++ memanfaatkan enable_if
.
void func(const pair<int, int>&);
void func(const pair<string, string>&);
func(make_pair("foo", "bar"));
Dalam contoh ini, make_pair("foo", "bar")
mengembalikan pair<const char *, const char *>
. Resolusi kelebihan beban harus menentukan mana yang func()
Anda inginkan. pair<A, B>
memiliki konstruktor yang mengonversi secara implisit dari pair<X, Y>
. Ini bukan baru—itu ada di C++98. Namun, di C++98/03, tanda tangan konstruktor yang dikonversi secara implisit selalu ada, bahkan jika itu pair<int, int>(const pair<const char *, const char *>&)
adalah . Resolusi kelebihan beban tidak peduli bahwa upaya untuk membuat instans bahwa konstruktor meledak secara mengerikan karena const char *
tidak secara implisit dapat dikonversi ke int
; itu hanya melihat tanda tangan, sebelum definisi fungsi dibuat. Oleh karena itu, kode contoh ambigu, karena tanda tangan ada untuk dikonversi pair<const char *, const char *>
ke dan pair<int, int>
pair<string, string>
.
C++11 memecahkan ambiguitas ini dengan menggunakan enable_if
untuk memastikan pair<A, B>(const pair<X, Y>&)
hanya ada ketika const X&
secara implisit dapat dikonversi ke A
dan const Y&
secara implisit dapat dikonversi ke B
. Ini memungkinkan resolusi kelebihan beban untuk menentukan bahwa pair<const char *, const char *>
tidak dapat dikonversi ke pair<int, int>
dan bahwa kelebihan beban yang diperlukan pair<string, string>
layak.
Persyaratan
Header: <type_traits>
kumpulan nama XML: std