0Pricing
C++ Academy · Lekcja

Częściowa specjalizacja

Specjalizuj wzorce szablonów

Częściowa specjalizacja to bezpłatna lekcja C++ Academy na CoddyKit. To lekcja 2 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 częściowa specjalizacja

Częściowa specjalizacja dostosowuje szablon do rodziny typów współdzielących określony wzorzec, a nie do jednego dokładnego typu.

  • Obsługują ją wyłącznie szablony klas.
  • Część parametrów pozostaje ogólna.
#include <iostream>

template <typename T>
struct Traits { static const char* kind() { return "value"; } };

template <typename T>
struct Traits<T*> { static const char* kind() { return "pointer"; } };

int main() {
    std::cout << Traits<int>::kind() << '\n';
    std::cout << Traits<int*>::kind() << '\n';
    return 0;
}

Dopasowywanie wskaźników

Wzorzec T* pasuje do dowolnego typu wskaźnikowego, dzięki czemu można obsłużyć wszystkie wskaźniki za pomocą jednej specjalizacji.

#include <iostream>

template <typename T>
struct Deref { static T get(T v) { return v; } };

template <typename T>
struct Deref<T*> { static T get(T* p) { return *p; } };

int main() {
    int x = 42;
    std::cout << Deref<int>::get(7) << '\n';
    std::cout << Deref<int*>::get(&x) << '\n';
    return 0;
}

Funkcji nie można częściowo specjalizować

Tylko szablony klas (i zmiennych) obsługują częściową specjalizację. W przypadku funkcji należy użyć przeciążania.

#include <iostream>

template <typename T>
void show(T) { std::cout << "value\n"; }

template <typename T>
void show(T*) { std::cout << "pointer\n"; }

int main() {
    int x = 0;
    show(5);
    show(&x);
    return 0;
}

Specjalizacja jednego z dwóch parametrów

W przypadku wielu parametrów typów można ustalić jeden z nich, a drugi pozostawić otwarty, dopasowując wzorzec obejmujący różne typy.

#include <iostream>

template <typename A, typename B>
struct Pair { static const char* kind() { return "mixed"; } };

template <typename A>
struct Pair<A, A> { static const char* kind() { return "same types"; } };

int main() {
    std::cout << Pair<int, double>::kind() << '\n';
    std::cout << Pair<int, int>::kind() << '\n';
    return 0;
}

Dopasowywanie tablic

Typy tablic można dopasowywać za pomocą wzorca, który przechwytuje typ elementu i rozmiar jako parametr szablonu niebędący typem.

#include <iostream>

template <typename T>
struct Info { static int size() { return 1; } };

template <typename T, int N>
struct Info<T[N]> { static int size() { return N; } };

int main() {
    std::cout << Info<int>::size() << '\n';
    std::cout << Info<int[5]>::size() << '\n';
    return 0;
}

Wzorce const

Specjalizacja może usuwać kwalifikator const lub go wykrywać, dopasowując const T jako wzorzec.

#include <iostream>

template <typename T>
struct IsConst { static const bool value = false; };

template <typename T>
struct IsConst<const T> { static const bool value = true; };

int main() {
    std::cout << std::boolalpha;
    std::cout << IsConst<int>::value << '\n';
    std::cout << IsConst<const int>::value << '\n';
    return 0;
}

Pierwszeństwo ma najbardziej wyspecjalizowana

Gdy pasować może kilka specjalizacji, kompilator wybiera najbardziej wyspecjalizowaną, czyli tę o najbardziej szczegółowym wzorcu.

#include <iostream>

template <typename T>
struct K { static int v() { return 0; } };

template <typename T>
struct K<T*> { static int v() { return 1; } };

template <>
struct K<int*> { static int v() { return 2; } };

int main() {
    std::cout << K<double*>::v() << ' ' << K<int*>::v() << '\n';
    return 0;
}

Wzorce referencji

Można również dopasowywać typy referencyjne, odróżniając referencję od zwykłej wartości.

#include <iostream>

template <typename T>
struct Cat { static const char* k() { return "value"; } };

template <typename T>
struct Cat<T&> { static const char* k() { return "lvalue ref"; } };

int main() {
    std::cout << Cat<int>::k() << '\n';
    std::cout << Cat<int&>::k() << '\n';
    return 0;
}

Tworzenie cech typów

Częściowa specjalizacja stanowi podstawę cech typów. Oto samodzielnie zaimplementowana cecha remove_pointer.

#include <iostream>
#include <type_traits>

template <typename T>
struct RemovePtr { using type = T; };

template <typename T>
struct RemovePtr<T*> { using type = T; };

int main() {
    std::cout << std::boolalpha;
    std::cout << std::is_same<RemovePtr<int*>::type, int>::value << '\n';
    return 0;
}

Łączenie wzorców

Można łączyć wzorce, na przykład dopasowując wskaźnik do const, aby obsługiwać wielowarstwowe struktury typów.

#include <iostream>

template <typename T>
struct Desc { static const char* k() { return "plain"; } };

template <typename T>
struct Desc<const T*> { static const char* k() { return "ptr to const"; } };

int main() {
    std::cout << Desc<int>::k() << '\n';
    std::cout << Desc<const int*>::k() << '\n';
    return 0;
}

Praktyczna cecha kontenera

Za pomocą częściowej specjalizacji można wyodrębnić typ elementu z szablonu przypominającego kontener.

#include <iostream>
#include <type_traits>

template <typename C>
struct Element { using type = void; };

template <template <typename> class C, typename T>
struct Element<C<T>> { using type = T; };

template <typename T>
struct Box { T item; };

int main() {
    std::cout << std::boolalpha;
    std::cout << std::is_same<Element<Box<int>>::type, int>::value << '\n';
    return 0;
}

Szybkie sprawdzenie

Proszę sprawdzić swoje rozumienie częściowej specjalizacji.

Podsumowanie

Poznali Państwo częściową specjalizację:

  • dostosowuje szablon klasy do wzorca typów, takiego jak T* lub const T
  • w przypadku funkcji używa się przeciążania, a nie częściowej specjalizacji
  • wybierana jest najlepiej dopasowana, najbardziej wyspecjalizowana wersja
  • stanowi podstawę cech typów, takich jak remove_pointer

Następnie poznają Państwo SFINAE — mechanizm pozwalający włączać funkcje tylko wtedy, gdy typ spełnia wymagania.

Często zadawane pytania

Czy lekcja „Częściowa specjalizacja” jest bezpłatna?

Tak — pełny tekst „Częściowa specjalizacja” 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 „Częściowa specjalizacja”?

Specjalizuj wzorce szablonów Ć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 2 z 4.

Ile czasu zajmuje lekcja „Częściowa specjalizacja”?

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