0Pricing
C++ Academy · Lekcja

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 ::type tylko 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_t i łą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

  1. Pełna specjalizacja
  2. Częściowa specjalizacja
  3. SFINAE
  4. Wzorce enable_if
← Powrót do C++ Academy