Last modified: January 31, 2019
This article is written in: 馃嚨馃嚤
Szablony (ang. templates) stanowi膮 fundament nowoczesnego programowania w j臋zyku C++. S膮 jednym z najbardziej pot臋偶nych narz臋dzi oferowanych przez ten j臋zyk, umo偶liwiaj膮c programistom pisanie bardziej elastycznego i wielokrotnego u偶ytku kodu. Dzi臋ki szablonom, mo偶na tworzy膰 funkcje i klasy, kt贸re dzia艂aj膮 z r贸偶nymi typami danych, co znacz膮co redukuje potrzeb臋 duplikacji kodu oraz zwi臋ksza jego czytelno艣膰 i utrzymanie. Szablony odgrywaj膮 kluczow膮 rol臋 w metaprogramowaniu w C++, pozwalaj膮c na wykonywanie oblicze艅 na etapie kompilacji oraz optymalizacj臋 kodu wynikowego. Poni偶ej przedstawiono szczeg贸艂owe om贸wienie r贸偶nych aspekt贸w szablon贸w w C++, wraz z przyk艂adami i wyja艣nieniami.
Szablony funkcji pozwalaj膮 na definiowanie funkcji, kt贸re dzia艂aj膮 na r贸偶nych typach danych. Umo偶liwiaj膮 one tworzenie generycznego kodu, kt贸ry jest bardziej uniwersalny i mo偶e by膰 stosowany w szerokim zakresie zastosowa艅 bez konieczno艣ci pisania osobnych wersji funkcji dla ka偶dego typu danych. Og贸lna sk艂adnia definicji szablonu funkcji jest nast臋puj膮ca:
template <parametry_szablonu>
typ_zwracany nazwa_funkcji(argumenty) {
// cia艂o funkcji
}
Przyk艂ad:
Definicja generycznej funkcji max2
, kt贸ra zwraca wi臋ksz膮 z dw贸ch warto艣ci:
template <typename t="">
T max2(T arg1, T arg2) {
return arg1 > arg2 ? arg1 : arg2;
}
template <typename T>
deklaruje szablon z parametrem typu T
, kt贸ry mo偶e by膰 dowolnym typem danych (np. int
, double
, std::string
).max2
przyjmuje dwa argumenty typu T
i zwraca warto艣膰 typu T
.?:
zwraca arg1
lub arg2
w zale偶no艣ci od wyniku por贸wnania arg1 > arg2
, co pozwala na elastyczne por贸wnywanie r贸偶nych typ贸w danych.U偶ycie funkcji szablonowej:
Szablony funkcji s膮 wykorzystywane poprzez ich instancjowanie z konkretnymi typami danych, co pozwala na ich wielokrotne u偶ycie bez konieczno艣ci definiowania nowych funkcji dla ka偶dego typu.
int a = max2<int>(10, 20); // Wynik: 20
double b = max2<double>(16.2, 3.14); // Wynik: 16.2
char c = max2<char>('a', 'b'); // Wynik: 'b'
Podczas kompilacji, gdy funkcja szablonowa jest wywo艂ywana z konkretnym typem, kompilator tworzy jej instancj臋 dla tego typu. Proces ten nazywany jest instancjacj膮 szablonu. Dzi臋ki temu generowany kod jest zoptymalizowany pod k膮tem u偶ytych typ贸w, eliminuj膮c narzut wydajno艣ciowy zwi膮zany z polimorfizmem dynamicznym. Instancjacja szablon贸w pozwala na tworzenie specjalizowanych wersji funkcji lub klas, kt贸re s膮 dostosowane do specyficznych potrzeb aplikacji, co zwi臋ksza efektywno艣膰 i wydajno艣膰 kodu.
Szablony klas umo偶liwiaj膮 definiowanie klas generycznych, kt贸re mog膮 operowa膰 na r贸偶nych typach danych. Dzi臋ki temu mo偶na tworzy膰 bardziej elastyczne i wielokrotnego u偶ytku struktury danych oraz obiekt贸w. Sk艂adnia szablonu klasy jest podobna do szablonu funkcji, co u艂atwia zrozumienie i implementacj臋.
Przyk艂ad:
Definicja szablonu klasy Box
:
template <typename t="">
class Box {
private:
T content;
public:
Box(T content) : content(content) {}
T getContent() const { return content; }
};
template <typename T>
: Deklaruje szablon klasy z parametrem typu T
, co pozwala na przechowywanie r贸偶nych typ贸w danych w jednej klasie.T content;
: Zmienna cz艂onkowska przechowuj膮ca zawarto艣膰 typu T
, co umo偶liwia elastyczne przechowywanie dowolnego typu danych.getContent()
operuj膮 na typie T
, co zapewnia, 偶e klasa Box
jest w pe艂ni generyczna i mo偶e by膰 u偶ywana z dowolnym typem danych.Tworzenie instancji szablonu klasy:
Szablony klas s膮 wykorzystywane poprzez okre艣lenie konkretnego typu danych podczas tworzenia obiektu.
Box<int> intBox(42);
Box<std::string> stringBox("Witaj");
Szablony mog膮 przyjmowa膰 wiele parametr贸w, zar贸wno typ贸w, jak i warto艣ci sta艂ych. Pozwala to na bardziej precyzyjne parametryzowanie kodu, co zwi臋ksza jego elastyczno艣膰 i umo偶liwia tworzenie bardziej zaawansowanych struktur danych oraz algorytm贸w.
Przyk艂ad:
Szablon klasy Array
z dwoma parametrami:
template <typename size="" std::size_t="" t,="">
class Array {
private:
T elements[Size];
public:
// Metody dost臋pu i modyfikacji element贸w
};
U偶ycie:
Array<int, 5=""> myArray;
W tym przyk艂adzie, szablon klasy Array
przyjmuje zar贸wno typ danych T
, jak i sta艂膮 Size
, co pozwala na tworzenie tablic o dynamicznie okre艣lonym rozmiarze i typie danych.
Czasami istnieje potrzeba dostosowania zachowania szablonu dla konkretnego typu. W takich przypadkach u偶ywamy specjalizacji szablonu, co pozwala na definiowanie unikalnych implementacji dla wybranych typ贸w danych, zachowuj膮c jednocze艣nie og贸lno艣膰 szablonu dla innych typ贸w.
Przyk艂ad:
Specjalizacja szablonu klasy Box
dla typu std::string
:
template <>
class Box<std::string> {
private:
std::string content;
public:
Box(std::string content) : content(content) {}
std::string getContent() const { return "Zawarto艣膰: " + content; }
};
template <>
: Wskazuje pe艂n膮 specjalizacj臋 szablonu, co oznacza, 偶e ta definicja jest unikalna dla okre艣lonego typu.class Box<std::string>
: Specjalizacja szablonu Box
dla typu std::string
umo偶liwia dostosowanie zachowania klasy do specyfiki tego typu danych.getContent()
zosta艂a zmodyfikowana, aby zwraca膰 prefiksowany ci膮g znak贸w, co jest specyficzne dla typu std::string
i nie by艂oby konieczne dla innych typ贸w.Mo偶emy definiowa膰 warto艣ci domy艣lne dla parametr贸w szablonu, co zwi臋ksza elastyczno艣膰 ich u偶ycia. Dzi臋ki warto艣ciom domy艣lnym, programista mo偶e tworzy膰 instancje szablon贸w bez konieczno艣ci podawania wszystkich parametr贸w, co upraszcza kod i poprawia jego czytelno艣膰.
Przyk艂ad:
template <typename size="10" std::size_t="" t="int,">
class Array {
private:
T elements[Size];
public:
// Implementacja metod
};
U偶ycie:
Array<> defaultArray; // Typ T=int, Size=10
Array<double, 5=""> customArray; // Typ T=double, Size=5
W tym przyk艂adzie, szablon klasy Array
ma zdefiniowane warto艣ci domy艣lne dla parametr贸w T
i Size
, co pozwala na tworzenie instancji z domy艣lnymi ustawieniami lub z niestandardowymi parametrami w zale偶no艣ci od potrzeb.
Od C++14 mo偶liwe jest definiowanie szablon贸w zmiennych, co pozwala na tworzenie zmiennych parametryzowanych typem. Szablony zmiennych s膮 szczeg贸lnie przydatne w przypadku sta艂ych warto艣ci, kt贸re mog膮 by膰 r贸偶ne w zale偶no艣ci od typu danych.
Przyk艂ad:
template<typename t="">
constexpr T pi = T(3.1415926535897932385);
auto floatPi = pi<float>;
auto doublePi = pi<double>;
Wyja艣nienie:
constexpr
oznacza, 偶e warto艣膰 jest sta艂a w czasie kompilacji, co pozwala na optymalizacj臋 i redukcj臋 koszt贸w czasowych w czasie wykonywania programu.pi<T>
jest zmienn膮 szablonow膮 parametryzowan膮 typem T
, co umo偶liwia tworzenie precyzyjnych wersji sta艂ej pi
dla r贸偶nych typ贸w danych, takich jak float
czy double
.C++11 wprowadzi艂 mo偶liwo艣膰 tworzenia alias贸w szablon贸w za pomoc膮 s艂owa kluczowego using
. Aliasowanie szablon贸w u艂atwia prac臋 z z艂o偶onymi typami szablonowymi, poprawiaj膮c czytelno艣膰 kodu oraz zmniejszaj膮c jego z艂o偶ono艣膰.
Przyk艂ad:
template <typename t="">
using Vec = std::vector<t>;
Vec<int> intVector;
Vec<double> doubleVector;
W tym przyk艂adzie, alias Vec
jest u偶ywany do reprezentowania std::vector<T>
, co upraszcza deklaracj臋 wektor贸w r贸偶nych typ贸w i poprawia czytelno艣膰 kodu.
Od C++20 mo偶na tworzy膰 szablony funkcji lambda, co dodatkowo zwi臋ksza mo偶liwo艣ci programistyczne. Szablony lambda pozwalaj膮 na definiowanie anonimowych funkcji generycznych, kt贸re mog膮 by膰 wykorzystywane w r贸偶nych kontekstach bez potrzeby definiowania osobnych funkcji.
Przyk艂ad:
auto lambda = []<typename t="">(T a, T b) {
return a + b;
};
auto sumInt = lambda(5, 3); // Wynik: 8
auto sumDouble = lambda(2.5, 1.5); // Wynik: 4.0
W tym przyk艂adzie, lambda jest szablonem funkcji, kt贸ry mo偶e przyjmowa膰 r贸偶ne typy danych T
i wykonywa膰 na nich operacj臋 dodawania, co czyni j膮 niezwykle elastyczn膮 i wielokrotnego u偶ytku.
Metaprogramowanie szablonowe to technika, kt贸ra wykorzystuje szablony do wykonywania oblicze艅 na etapie kompilacji. Pozwala to na optymalizacj臋 kodu oraz wykonywanie skomplikowanych oblicze艅 bez narzutu w czasie wykonywania programu. Metaprogramowanie szablonowe jest szczeg贸lnie przydatne w przypadkach, gdzie wydajno艣膰 jest kluczowa, a obliczenia mog膮 by膰 przeprowadzone wcze艣niej, podczas kompilacji.
Obliczanie warto艣ci ci膮gu Fibonacciego za pomoc膮 szablon贸w:
template<int n="">
struct Fibonacci {
static_assert(N >= 0, "N musi by膰 nieujemne");
static constexpr int value = Fibonacci<n -="" 1="">::value + Fibonacci<n -="" 2="">::value;
};
template<>
struct Fibonacci<0> {
static constexpr int value = 0;
};
template<>
struct Fibonacci<1> {
static constexpr int value = 1;
};
constexpr int fib10 = Fibonacci<10>::value; // Wynik: 55
Fibonacci
jest rekurencyjnie instancjonowana dla warto艣ci N
, a偶 do osi膮gni臋cia przypadk贸w bazowych, takich jak N=0
i N=1
, co pozwala na obliczenia w trakcie kompilacji.static_assert
jest u偶ywany do sprawdzania warunk贸w w czasie kompilacji, co pozwala na weryfikacj臋 poprawno艣ci kodu przed jego wykonaniem. W tym przypadku, zapewnia, 偶e N
jest nieujemne.constexpr
zapewnia, 偶e dana warto艣膰 zostanie obliczona w czasie kompilacji, co zwi臋ksza efektywno艣膰 i pozwala na lepsz膮 optymalizacj臋 kodu.Ci膮g Fibonacciego jest zdefiniowany rekurencyjnie:
$$ F(0) = 0, \quad F(1) = 1, \quad F(N) = F(N-1) + F(N-2) \text{ dla } N \geq 2 $$
Implementacja za pomoc膮 szablon贸w odwzorowuje t臋 definicj臋, pozwalaj膮c kompilatorowi na obliczenie warto艣ci F(N)
podczas kompilacji. Dzi臋ki temu, warto艣ci ci膮gu Fibonacciego s膮 dost臋pne w czasie kompilacji, co mo偶e by膰 u偶yteczne w r贸偶nych optymalizacjach i zastosowaniach.
static_assert
, kt贸ry pozwala na weryfikacj臋 za艂o偶e艅 programu przed jego uruchomieniem, eliminuj膮c potencjalne b艂臋dy ju偶 na etapie kompilacji. Dzi臋ki temu, programista mo偶e szybko zidentyfikowa膰 i naprawi膰 b艂臋dy, zanim program zostanie uruchomiony.Szablony s膮 integraln膮 cz臋艣ci膮 j臋zyka C++ i stanowi膮 podstaw臋 wielu bibliotek oraz aplikacji komercyjnych. Ich zdolno艣膰 do tworzenia kodu generycznego, kt贸ry mo偶e dzia艂a膰 z r贸偶nymi typami danych, sprawia, 偶e s膮 one niezb臋dne w nowoczesnym programowaniu. W tej sekcji przyjrzymy si臋, jak szablony s膮 wykorzystywane w praktyce, skupiaj膮c si臋 na standardowej bibliotece C++ (STL) oraz na innych popularnych bibliotekach, takich jak Boost czy Eigen.
STL (Standard Template Library) jest zestawem klas i funkcji szablonowych dostarczanych przez standardow膮 bibliotek臋 C++. Zosta艂a ona zaprojektowana w celu zapewnienia programistom gotowych do u偶ycia struktur danych oraz algorytm贸w, kt贸re s膮 zar贸wno wydajne, jak i 艂atwe w u偶yciu. STL jest szeroko stosowana w r贸偶nych aplikacjach, od prostych program贸w konsolowych po zaawansowane systemy o du偶ej skali.
Kontenery s膮 klasami szablonowymi, kt贸re przechowuj膮 kolekcje obiekt贸w. Dzi臋ki szablonom mog膮 one przechowywa膰 elementy dowolnego typu, co czyni je niezwykle elastycznymi i wielokrotnego u偶ytku. Kontenery w STL s膮 zoptymalizowane pod k膮tem r贸偶nych operacji, takich jak dodawanie, usuwanie czy wyszukiwanie element贸w, co pozwala na efektywne zarz膮dzanie danymi.
Oto niekt贸re z najwa偶niejszych kontener贸w w STL:
Kontener | Opis |
std::vector |
Dynamiczna tablica o zmiennym rozmiarze. |
std::list |
Lista dwukierunkowa. |
std::deque |
Dwustronna kolejka. |
std::set |
Zbi贸r unikalnych element贸w, uporz膮dkowanych. |
std::map |
Asocjacyjny kontener przechowuj膮cy pary klucz-warto艣膰. |
std::unordered_set |
Nieuporz膮dkowany zbi贸r wykorzystuj膮cy tablice haszuj膮ce. |
std::unordered_map |
Nieuporz膮dkowana mapa wykorzystuj膮ca tablice haszuj膮ce do par klucz-warto艣膰. |
Ka偶dy z tych kontener贸w ma swoje specyficzne zastosowania i jest zoptymalizowany pod k膮tem r贸偶nych operacji, co pozwala programistom na wyb贸r najbardziej odpowiedniego kontenera dla ich potrzeb.
Algorytmy w STL s膮 funkcjami szablonowymi, kt贸re wykonuj膮 operacje na danych przechowywanych w kontenerach. S膮 one niezale偶ne od konkretnych typ贸w danych i kontener贸w, o ile dostarczone s膮 odpowiednie iteratory. Algorytmy w STL obejmuj膮 szeroki zakres operacji, takich jak sortowanie, wyszukiwanie, modyfikowanie czy transformowanie danych, co pozwala na efektywne i elastyczne manipulowanie kolekcjami danych.
Funkcja | Opis |
std::sort |
Sortowanie element贸w w zakresie. |
std::find |
Wyszukiwanie elementu w zakresie. |
std::accumulate |
Sumowanie warto艣ci w zakresie. |
std::copy |
Kopiowanie element贸w z jednego zakresu do drugiego. |
Algorytmy te s膮 zoptymalizowane pod k膮tem wydajno艣ci i mog膮 by膰 stosowane do r贸偶nych typ贸w danych, co czyni je niezwykle wszechstronnymi narz臋dziami w arsenale programisty C++.
Iteratory s膮 abstrakcj膮 wska藕nik贸w, kt贸re pozwalaj膮 na jednolite interfejsy do przegl膮dania element贸w w kontenerach. S膮 one zaimplementowane jako szablony, dzi臋ki czemu mog膮 dzia艂a膰 z r贸偶nymi typami kontener贸w. Iteratory umo偶liwiaj膮 programistom pisanie bardziej generycznego i elastycznego kodu, kt贸ry mo偶e dzia艂a膰 z dowolnym kontenerem, kt贸ry wspiera dany typ iteratora.
std::vector
std::vector
jest jednym z najcz臋艣ciej u偶ywanych kontener贸w w STL. Reprezentuje dynamiczn膮 tablic臋, kt贸ra mo偶e zmienia膰 sw贸j rozmiar w czasie wykonywania programu. Dzi臋ki wykorzystaniu szablon贸w, std::vector
mo偶e przechowywa膰 elementy dowolnego typu, co czyni go niezwykle elastycznym narz臋dziem do zarz膮dzania dynamicznymi kolekcjami danych.
Definicja szablonu std::vector
:
W uproszczeniu, std::vector
jest zdefiniowany nast臋puj膮co:
template <typename allocator="std::allocator<T" t,="" typename="">>
class vector {
// Implementacja wewn臋trzna
};
Parametry szablonu:
typename T
okre艣la typ przechowywanych element贸w, co pozwala na tworzenie szablon贸w, kt贸re mog膮 dzia艂a膰 z r贸偶nymi typami danych.typename Allocator
definiuje typ alokatora u偶ywanego do zarz膮dzania pami臋ci膮, z domy艣ln膮 warto艣ci膮 std::allocator<T>
, co umo偶liwia elastyczne zarz膮dzanie pami臋ci膮 dla element贸w.Przyk艂ady u偶ycia:
std::vector<int> vecInt; // Wektor liczb ca艂kowitych
std::vector<double> vecDouble; // Wektor liczb zmiennoprzecinkowych
std::vector<std::string> vecString; // Wektor 艂a艅cuch贸w znak贸w
W tym przyk艂adzie, std::vector
jest u偶ywany do przechowywania r贸偶nych typ贸w danych, co pokazuje jego elastyczno艣膰 i wszechstronno艣膰. Dzi臋ki szablonom, mo偶na 艂atwo tworzy膰 wektory dla dowolnego typu danych, co znacznie u艂atwia zarz膮dzanie dynamicznymi kolekcjami.
Boost to zestaw bibliotek C++ rozszerzaj膮cych funkcjonalno艣膰 standardowej biblioteki. Wiele z nich jest proponowanych do w艂膮czenia do standardu C++. Szablony s膮 intensywnie wykorzystywane w celu zapewnienia elastyczno艣ci i wydajno艣ci.
Przyk艂ad: boost::shared_ptr
Przed wprowadzeniem std::shared_ptr
w C++11, boost::shared_ptr
by艂 szeroko stosowanym inteligentnym wska藕nikiem zarz膮dzaj膮cym 偶yciem obiektu.
Definicja:
template<typename t="">
class shared_ptr {
// Implementacja wewn臋trzna
};
U偶ycie:
boost::shared_ptr<myclass> ptr(new MyClass());
Zalety:
Eigen to szablonowa biblioteka C++ do algebry liniowej, zoptymalizowana pod k膮tem wysokiej wydajno艣ci.
Definicja szablonu macierzy:
template<typename colsatcompiletime="" int="" rowsatcompiletime,="" scalar,="">
class Matrix {
// Implementacja wewn臋trzna
};
Przyk艂ad u偶ycia:
Eigen::Matrix<float, 3="" 3,=""> matA;
Eigen::Matrix<float, 1="" 3,=""> vecB;
matA << 1, 2, 3,
4, 5, 6,
7, 8, 9;
vecB << 1,
2,
3;
Eigen::Matrix<float, 1="" 3,=""> result = matA * vecB;
W艂a艣ciwo艣ci:
Analiza wydajno艣ci:
Koncepty wprowadzaj膮 mo偶liwo艣膰 definiowania wymaga艅 dla parametr贸w szablonu, co u艂atwia tworzenie bardziej czytelnego i bezpiecznego kodu.
Przyk艂ad:
template<typename t="">
concept Number = std::is_arithmetic_v<t>;
template<number t="">
T multiply(T a, T b) {
return a * b;
}
Zalety:
W miar臋 rozwoju j臋zyka C++, szablony sta艂y si臋 nie tylko narz臋dziem do tworzenia generycznego kodu, ale tak偶e platform膮 do implementacji zaawansowanych technik programistycznych. W tej sekcji om贸wimy kilka z tych zaawansowanych technik, kt贸re pozwalaj膮 na jeszcze wi臋ksz膮 elastyczno艣膰 i moc w tworzeniu aplikacji. Skoncentrujemy si臋 na szablonach o zmiennej liczbie argument贸w, wyra偶eniach constexpr
w szablonach, szablonach wewn臋trznych (CRTP), a tak偶e na om贸wieniu ogranicze艅 i wyzwa艅 zwi膮zanych z ich u偶ywaniem. Dodatkowo, przedstawimy praktyczne wskaz贸wki, kt贸re pomog膮 w efektywnym wykorzystaniu tych technik w codziennym programowaniu.
Szablony o zmiennej liczbie argument贸w, znane r贸wnie偶 jako variadic templates, zosta艂y wprowadzone w standardzie C++11 i stanowi膮 pot臋偶ne rozszerzenie tradycyjnych szablon贸w. Umo偶liwiaj膮 one definiowanie funkcji i klas, kt贸re mog膮 przyjmowa膰 dowoln膮 liczb臋 parametr贸w, co jest niezwykle przydatne w sytuacjach, gdy liczba argument贸w nie jest znana z g贸ry lub mo偶e si臋 dynamicznie zmienia膰.
Przyk艂ad: Funkcja print
wy艣wietlaj膮ca dowoln膮 liczb臋 argument贸w:
#include <iostream>
template<typename... args="">
void print(Args... args) {
(std::cout << ... << args) << std::endl;
}
int main() {
print(1, 2, 3); // Wy艣wietla: 123
print("Witaj, ", "艣wiecie!"); // Wy艣wietla: Witaj, 艣wiecie!
return 0;
}
template<typename... Args>
: Deklaruje szablon z pakietem typ贸w Args
. Operator ...
oznacza, 偶e Args
mo偶e reprezentowa膰 dowoln膮 liczb臋 typ贸w.Args... args
: Pakiet argument贸w funkcji. Podobnie jak powy偶ej, ...
wskazuje na zmienn膮 liczb臋 argument贸w.(std::cout << ... << args)
: Fold expression, dost臋pne od C++17, kt贸re umo偶liwia sk艂adanie wyra偶e艅 binarnych. W tym przypadku, 艂膮czy wszystkie argumenty za pomoc膮 operatora <<
i wypisuje je na standardowe wyj艣cie.Zastosowanie:
Szablony o zmiennej liczbie argument贸w s膮 niezwykle przydatne w tworzeniu funkcji, kt贸re musz膮 obs艂ugiwa膰 dynamiczn膮 liczb臋 parametr贸w, takich jak funkcje loguj膮ce, formatowania czy tworzenia kontener贸w o zmiennym rozmiarze.
constexpr
w SzablonachS艂owo kluczowe constexpr
zosta艂o wprowadzone w C++11 i pozwala na wykonywanie oblicze艅 w czasie kompilacji. W po艂膮czeniu z szablonami, constexpr
umo偶liwia tworzenie funkcji, kt贸re zwracaj膮 sta艂e warto艣ci zale偶ne od parametr贸w szablonu, co mo偶e prowadzi膰 do znacznych optymalizacji kodu.
Przyk艂ad: Funkcja square
obliczaj膮ca kwadrat liczby:
#include <iostream>
template<typename t="">
constexpr T square(T x) {
return x * x;
}
int main() {
constexpr int squareOfFive = square(5); // Wynik: 25
std::cout << "Kwadrat 5 to: " << squareOfFive << std::endl;
return 0;
}
template<typename T>
: Deklaruje szablon funkcji z parametrem typu T
.constexpr T square(T x)
: Funkcja oznaczona jako constexpr
, co oznacza, 偶e mo偶e by膰 oceniona w czasie kompilacji, je艣li argumenty s膮 znane w tym czasie.constexpr int squareOfFive = square(5);
: Inicjalizuje sta艂膮 squareOfFive
wynikiem funkcji square(5)
, kt贸ry jest obliczany w czasie kompilacji.Zastosowanie:
Funkcje constexpr
s膮 u偶yteczne w przypadkach, gdzie potrzebne s膮 sta艂e warto艣ci obliczane na podstawie parametr贸w szablonu, co mo偶e prowadzi膰 do bardziej wydajnego kodu dzi臋ki wst臋pnej ocenie wyra偶e艅.
Curiously Recurring Template Pattern (CRTP) to idiom programistyczny, w kt贸rym klasa dziedziczy po szablonie swojej w艂asnej klasy. Technika ta pozwala na osi膮gni臋cie statycznego polimorfizmu oraz umo偶liwia implementacj臋 funkcji, kt贸re s膮 specyficzne dla klasy pochodnej, bez u偶ycia wirtualnych metod.
Przyk艂ad:
#include <iostream>
// Szablon bazowej klasy wykorzystuj膮cy CRTP
template<typename derived="">
class Base {
public:
void interface() {
// Wywo艂uje implementacj臋 specyficzn膮 dla klasy pochodnej
static_cast<derived*>(this)->implementation();
}
void commonFunction() {
std::cout << "Funkcja wsp贸lna w klasie Base." << std::endl;
}
};
// Klasa pochodna dziedzicz膮ca po Base za pomoc膮 CRTP
class DerivedClass : public Base<derivedclass> {
public:
void implementation() {
std::cout << "Implementacja specyficzna dla DerivedClass." << std::endl;
}
};
int main() {
DerivedClass obj;
obj.interface(); // Wywo艂uje DerivedClass::implementation()
obj.commonFunction(); // Wywo艂uje Base::commonFunction()
return 0;
}
template<typename Derived>
: Szablon bazowej klasy przyjmuj膮cy typ klasy pochodnej.static_cast<Derived*>(this)->implementation()
: Rzutowanie wska藕nika this
na typ klasy pochodnej i wywo艂anie jej metody implementation()
.DerivedClass : public Base<DerivedClass>
: Klasa pochodna dziedziczy po bazowej klasie szablonowej, przekazuj膮c siebie jako parametr szablonu.Zastosowania:
Mimo 偶e szablony oferuj膮 ogromne mo偶liwo艣ci, ich u偶ycie wi膮偶e si臋 r贸wnie偶 z pewnymi ograniczeniami i wyzwaniami, kt贸re programi艣ci powinni mie膰 na uwadze:
Aby skutecznie wykorzysta膰 zaawansowane techniki szablonowe i unikn膮膰 typowych pu艂apek, warto przestrzega膰 kilku praktycznych zasad:
#include <concepts>
template<std::integral t="">
T add(T a, T b) {
return a + b;
}