Wzorce enable_if
Ograniczaj szablony w klasyczny sposób
Wzorce enable_if to bezpłatna lekcja C++ Academy na CoddyKit. To lekcja 4 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej C++ Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs C++ Academy zawiera 4 lekcji w sumie.
Czym jest enable_if
std::enable_if to niewielka cecha, która warunkowo definiuje składową type. Gdy warunek jest prawdziwy, typ istnieje; gdy jest fałszywy, otaczający szablon zostaje usunięty przez SFINAE.
- Znajduje się w
<type_traits>. - Jest klasycznym narzędziem do ograniczania szablonów.
#include <iostream>
#include <type_traits>
template <typename T>
typename std::enable_if<std::is_integral<T>::value, T>::type
doubleIt(T v) { return v * 2; }
int main() {
std::cout << doubleIt(21) << '\n';
return 0;
}Jak to działa
enable_if<Cond, T>::type jest równe T tylko wtedy, gdy Cond jest prawdziwe. Jeśli warunek jest fałszywy, nie ma składowej type, więc podstawienie kończy się niepowodzeniem.
#include <iostream>
#include <type_traits>
int main() {
std::cout << std::boolalpha;
std::cout << std::is_same<std::enable_if<true, int>::type, int>::value << '\n';
return 0;
}enable_if w typie zwracanym
Najczęściej umieszcza się je w typie zwracanym. Funkcja istnieje tylko wtedy, gdy warunek jest spełniony.
#include <iostream>
#include <type_traits>
template <typename T>
typename std::enable_if<std::is_floating_point<T>::value, T>::type
half(T v) { return v / 2; }
int main() {
std::cout << half(5.0) << '\n';
return 0;
}enable_if jako parametr szablonu
Inny idiom umieszcza enable_if w domyślnym parametrze szablonu, dzięki czemu typ zwracany pozostaje czytelny.
#include <iostream>
#include <type_traits>
template <typename T, typename = typename std::enable_if<std::is_integral<T>::value>::type>
T triple(T v) { return v * 3; }
int main() {
std::cout << triple(4) << '\n';
return 0;
}Skrót enable_if_t
W C++14 dodano alias std::enable_if_t<Cond, T>, dzięki któremu można pominąć zapis typename ...::type.
#include <iostream>
#include <type_traits>
template <typename T>
std::enable_if_t<std::is_integral<T>::value, T>
negate(T v) { return -v; }
int main() {
std::cout << negate(8) << '\n';
return 0;
}Łączenie dwóch przeciążeń
Należy zapewnić uzupełniające się warunki, tak aby dla każdego typu poprawne było dokładnie jedno przeciążenie i nie występowała niejednoznaczność.
#include <iostream>
#include <type_traits>
template <typename T>
std::enable_if_t<std::is_integral<T>::value, const char*>
category() { return "integer"; }
template <typename T>
std::enable_if_t<!std::is_integral<T>::value, const char*>
category() { return "non-integer"; }
int main() {
std::cout << category<int>() << ' ' << category<double>() << '\n';
return 0;
}Łączenie warunków
Operatory logiczne zastosowane do wartości cech pozwalają wyrażać bardziej rozbudowane ograniczenia, takie jak „całkowity i ze znakiem”.
#include <iostream>
#include <type_traits>
template <typename T>
std::enable_if_t<std::is_integral<T>::value && std::is_signed<T>::value, T>
magnitude(T v) { return v < 0 ? -v : v; }
int main() {
std::cout << magnitude(-12) << '\n';
return 0;
}Ograniczanie konstruktora
Można umieścić enable_if w parametrze szablonu konstruktora, aby zezwolić na jego użycie tylko dla zgodnych typów.
#include <iostream>
#include <type_traits>
struct Wrapper {
int value;
template <typename T, typename = std::enable_if_t<std::is_integral<T>::value>>
Wrapper(T v) : value(static_cast<int>(v)) {}
};
int main() {
Wrapper w(42);
std::cout << w.value << '\n';
return 0;
}Pułapka domyślnego argumentu szablonu
Dwa przeciążenia różniące się wyłącznie domyślnym parametrem szablonu enable_if są traktowane jako ponowne definicje. Należy nadać im różne postacie, na przykład umieścić jeden z warunków w typie zwracanym.
#include <iostream>
#include <type_traits>
template <typename T>
std::enable_if_t<std::is_integral<T>::value, void>
printKind() { std::cout << "int\n"; }
template <typename T>
std::enable_if_t<std::is_floating_point<T>::value, void>
printKind() { std::cout << "float\n"; }
int main() {
printKind<int>();
printKind<double>();
return 0;
}Porównanie z concepts
Wprowadzone w C++20 concepts zastępują większość zastosowań enable_if znacznie czytelniejszą składnią, ale enable_if pozostaje niezbędne w kodzie sprzed C++20 i w niektórych szczególnych przypadkach.
#include <iostream>
#include <type_traits>
template <typename T>
std::enable_if_t<std::is_arithmetic<T>::value, T>
square(T v) { return v * v; }
int main() {
std::cout << square(6) << ' ' << square(1.5) << '\n';
return 0;
}Kompletny przykład
Połączmy wszystkie elementy: rodzinę funkcji, która formatuje liczby całkowite i zmiennoprzecinkowe w różny sposób, wybieraną w czasie kompilacji.
#include <iostream>
#include <type_traits>
template <typename T>
std::enable_if_t<std::is_integral<T>::value, void>
format(T v) { std::cout << "int[" << v << "]\n"; }
template <typename T>
std::enable_if_t<std::is_floating_point<T>::value, void>
format(T v) { std::cout << "float(" << v << ")\n"; }
int main() {
format(10);
format(3.5);
return 0;
}Szybkie sprawdzenie
Proszę sprawdzić swoje rozumienie enable_if.
Podsumowanie
Poznali Państwo klasyczne wzorce użycia enable_if:
- definiuje
::typetylko wtedy, gdy warunek jest prawdziwy, umożliwiając użycie SFINAE - jest umieszczane w typie zwracanym lub domyślnym parametrze szablonu
- należy używać aliasu
enable_if_ti łączyć cechy za pomocą operatorów logicznych - concepts zastępują je w C++20, ale pozostaje ono szeroko stosowane
To kończy kurs Specjalizacja szablonów i SFINAE.
Często zadawane pytania
Czy lekcja „Wzorce enable_if” jest bezpłatna?
Tak — pełny tekst „Wzorce enable_if” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu C++ Academy, przejdź na CoddyKit PRO. Kurs C++ Academy zawiera 4 lekcji w sumie.
Co nauczysz się w „Wzorce enable_if”?
Ograniczaj szablony w klasyczny sposób Ćwiczysz C++ Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.
Czy potrzebuję doświadczenia, aby zacząć C++ Academy?
Nie wymagamy żadnego doświadczenia. C++ Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 4 z 4.
Ile czasu zajmuje lekcja „Wzorce enable_if”?
Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.
Czy mogę pisać i uruchamiać kod w tej lekcji C++ Academy?
Tak. Każda lekcja C++ Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.
Wszystkie lekcje w tym kursie
- Pełna specjalizacja
- Częściowa specjalizacja
- SFINAE
- Wzorce enable_if