Bagikan melalui


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 = typenameakan 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 satu enable_if untuk CONDITION 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, gunakan static_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

Lihat juga

<type_traits>