SFINAE
Aktifkan fungsi secara kondisional
SFINAE adalah pelajaran C++ Academy gratis di CoddyKit. Ini adalah pelajaran 3 dari 4. Kamu bisa membaca pelajaran lengkapnya di bawah secara gratis — lalu praktikkan langsung di browser dengan editor kode bawaan dan tutor AI 24/7. Ini adalah bagian dari jalur belajar C++ Academy, dan progresmu tersinkronisasi di web dan aplikasi CoddyKit. Kursus C++ Academy mencakup 4 pelajaran total.
Apa Arti SFINAE?
SFINAE adalah singkatan dari "Kegagalan Substitusi Bukanlah Kesalahan". Ketika kompilator mengganti argumen templat dan hasilnya tidak valid, kandidat tersebut cukup dihapus tanpa menimbulkan kesalahan berat.
- Memungkinkan pembebanan berlebih bersyarat.
- Menjadi dasar pemilihan saat kompilasi.
#include <iostream>
#include <type_traits>
template <typename T>
typename std::enable_if<std::is_integral<T>::value, bool>::type
isOdd(T n) { return n % 2 != 0; }
int main() {
std::cout << std::boolalpha << isOdd(3) << '\n';
return 0;
}Kegagalan Substitusi dalam Praktik
Jika penggantian suatu tipe membuat tanda tangan fungsi tidak valid, kompilator akan melewatinya secara diam-diam dan terus memeriksa kandidat lainnya.
#include <iostream>
template <typename T>
auto sizeOfValue(T t) -> decltype(t.size()) { return t.size(); }
int main() {
std::string s = "hello";
std::cout << sizeOfValue(s) << '\n';
return 0;
}Dua Pembebanan Berlebih, Satu yang Menang
Sediakan dua pembebanan berlebih yang salah satunya saja berhasil disubstitusikan untuk tipe tertentu. SFINAE membuang yang tidak valid.
#include <iostream>
#include <type_traits>
template <typename T>
typename std::enable_if<std::is_integral<T>::value, const char*>::type
name() { return "integral"; }
template <typename T>
typename std::enable_if<std::is_floating_point<T>::value, const char*>::type
name() { return "floating"; }
int main() {
std::cout << name<int>() << ' ' << name<double>() << '\n';
return 0;
}decltype dan SFINAE Ekspresi
Menggunakan decltype pada suatu ekspresi dalam tipe kembalian memungkinkan fungsi hanya ada jika ekspresi tersebut valid untuk tipe itu.
#include <iostream>
template <typename T>
auto tryDouble(T x) -> decltype(x + x) { return x + x; }
int main() {
std::cout << tryDouble(21) << '\n';
std::cout << tryDouble(2.5) << '\n';
return 0;
}Mendeteksi Anggota
Trik SFINAE klasik mendeteksi apakah suatu tipe memiliki anggota tertentu dengan memeriksa apakah ekspresi yang menggunakannya dapat dikompilasi.
#include <iostream>
#include <type_traits>
#include <vector>
template <typename T>
auto hasSize(int) -> decltype(std::declval<T>().size(), std::true_type{});
template <typename T>
std::false_type hasSize(...);
int main() {
std::cout << std::boolalpha;
std::cout << decltype(hasSize<std::vector<int>>(0))::value << '\n';
std::cout << decltype(hasSize<int>(0))::value << '\n';
return 0;
}Alternatif ...
Pembebanan berlebih yang menerima ... (argumen variadik) memiliki prioritas terendah. Ini berfungsi sebagai penampung semua ketika pembebanan berlebih yang dibatasi SFINAE gagal.
#include <iostream>
template <typename T>
auto pick(int) -> decltype(T{}.value, void()) { std::cout << "has value\n"; }
template <typename T>
void pick(...) { std::cout << "no value\n"; }
struct WithValue { int value = 0; };
int main() {
pick<WithValue>(0);
pick<int>(0);
return 0;
}void_t
std::void_t pada C++17 menyederhanakan pendeteksian: semua tipe yang terbentuk dengan benar dipetakan ke void, sehingga spesialisasi hanya dipicu ketika ekspresi yang diperiksa valid.
#include <iostream>
#include <type_traits>
#include <vector>
template <typename T, typename = void>
struct HasSize : std::false_type {};
template <typename T>
struct HasSize<T, std::void_t<decltype(std::declval<T>().size())>> : std::true_type {};
int main() {
std::cout << std::boolalpha;
std::cout << HasSize<std::vector<int>>::value << '\n';
std::cout << HasSize<int>::value << '\n';
return 0;
}Mengapa Tidak Langsung Menjadi Kesalahan?
Tanpa SFINAE, substitusi yang tidak valid akan menjadi kesalahan kompilasi berat dan tidak dapat dipulihkan. SFINAE mengubahnya menjadi "bukan kandidat" secara diam-diam.
#include <iostream>
#include <type_traits>
template <typename T>
typename std::enable_if<std::is_pointer<T>::value, bool>::type
isNull(T p) { return p == nullptr; }
int main() {
int x = 0;
std::cout << std::boolalpha << isNull(&x) << '\n';
return 0;
}Alternatif Pengiriman Berdasarkan Penanda
SFINAE dapat sulit dibaca. Pengiriman berdasarkan penanda memilih implementasi menggunakan tipe penanda kecil dan resolusi pembebanan berlebih.
#include <iostream>
#include <type_traits>
template <typename T>
void impl(T v, std::true_type) { std::cout << "integral: " << v << '\n'; }
template <typename T>
void impl(T v, std::false_type) { std::cout << "other: " << v << '\n'; }
template <typename T>
void handle(T v) { impl(v, std::is_integral<T>{}); }
int main() {
handle(5);
handle(2.5);
return 0;
}SFINAE dan constexpr if
Pada C++17, if constexpr sering menggantikan SFINAE untuk percabangan di dalam satu fungsi, karena cabang yang tidak digunakan dibuang saat kompilasi.
#include <iostream>
#include <type_traits>
template <typename T>
void describe(T v) {
if constexpr (std::is_integral<T>::value) {
std::cout << "integral: " << v << '\n';
} else {
std::cout << "other: " << v << '\n';
}
}
int main() {
describe(7);
describe(3.14);
return 0;
}Menggabungkan Semuanya
SFINAE sangat berguna ketika Anda harus memilih di antara templat fungsi yang terpisah berdasarkan sifat tipe pada tingkat pembebanan berlebih.
#include <iostream>
#include <type_traits>
template <typename T>
typename std::enable_if<std::is_signed<T>::value, T>::type
absValue(T v) { return v < 0 ? -v : v; }
int main() {
std::cout << absValue(-9) << '\n';
return 0;
}Pemeriksaan Singkat
Uji pemahaman Anda tentang SFINAE.
Rangkuman
Anda telah mempelajari SFINAE:
- substitusi yang tidak valid menghapus kandidat alih-alih menimbulkan kesalahan
- digunakan bersama
enable_if,decltype, danvoid_tuntuk mengaktifkan fungsi secara bersyarat - pembebanan berlebih
...berfungsi sebagai cadangan - alternatif modernnya mencakup pengiriman berdasarkan penanda dan
if constexpr
Selanjutnya, Anda akan berfokus secara mendetail pada pola klasik enable_if.
Pertanyaan yang Sering Diajukan
Apakah pelajaran “SFINAE” gratis?
Ya — teks lengkap “SFINAE” gratis dibaca di sini di web. Untuk praktiknya secara interaktif (editor kode bawaan dan tutor AI 24/7) dan buka sisa kursus C++ Academy, upgrade ke CoddyKit PRO. Kursus C++ Academy mencakup 4 pelajaran total.
Apa yang akan aku pelajari di “SFINAE”?
Aktifkan fungsi secara kondisional Kamu berlatih C++ Academy dengan kode praktik yang langsung kamu jalankan di browser, dan tutor AI 24/7 menjawab pertanyaanmu saat kamu mengerjakan pelajaran ini.
Apakah aku perlu pengalaman untuk memulai C++ Academy?
Tidak diperlukan pengalaman sebelumnya. C++ Academy di CoddyKit dirancang untuk pemula hingga pelajar tingkat lanjut, jadi kamu bisa memulai di sini atau dari awal dan belajar sesuai kecepatan kamu sendiri. Ini adalah pelajaran 3 dari 4.
Berapa lama pelajaran “SFINAE” memakan waktu?
Sebagian besar pelajaran CoddyKit memakan waktu sekitar 5–10 menit. Setiap pelajaran ringkas dan interaktif, jadi kamu membuat kemajuan stabil dan melanjutkan dari tempat kamu tinggalkan di web dan aplikasi.
Bisakah aku menulis dan menjalankan kode dalam pelajaran C++ Academy ini?
Ya. Setiap pelajaran C++ Academy menyertakan editor kode bawaan, jadi kamu menulis dan menjalankan kode nyata langsung di browser dan mendapatkan umpan balik AI instan — tidak diperlukan penyiapan lokal.