А шаблон це простий, але дуже потужний інструмент на C++. Проста ідея полягає в тому, щоб передати тип даних як параметр, щоб нам не потрібно було писати той самий код для різних типів даних. Наприклад, розробнику програмного забезпечення може знадобитися sort() для різних типів даних. Замість того, щоб писати та підтримувати кілька кодів, ми можемо написати один sort() і передати тип даних як параметр.
C++ додає два нових ключових слова для підтримки шаблонів: 'шаблон' і 'typename' . Друге ключове слово завжди можна замінити ключовим словом «клас» .
Як працюють шаблони?
Шаблони розгортаються під час компіляції. Це як макроси. Різниця полягає в тому, що компілятор виконує перевірку типів перед розширенням шаблону. Ідея проста: вихідний код містить лише функцію/клас, але скомпільований код може містити кілька копій однієї функції/класу.
Шаблони функцій
Ми пишемо загальну функцію, яку можна використовувати для різних типів даних. Прикладами шаблонів функцій є sort(), max(), min(), printArray().
Щоб дізнатися більше про тему, див Дженерики в C++ .
приклад:
C++ // C++ Program to demonstrate // Use of template #include using namespace std; // One function works for all data types. This would work // even for user defined types if operator '>' є перевантаженим шаблономT myMax(T x, T y) { return (x> y)? x : y; } int main() { // Виклик myMax для int cout<< myMax (3, 7)<< endl; // call myMax for double cout << myMax(3,0, 7,0)<< endl; // call myMax for char cout << myMax('g', 'e')<< endl; return 0; }>
Вихід
7 7 g>
приклад: Реалізація Бульбашкове сортування використання шаблонів у C++
C++ // C++ Program to implement // Bubble sort // using template function #include using namespace std; // A template function to implement bubble sort. // We can use this for any data type that supports // comparison operator template void bubbleSort(T a[], int n) { for (int i = 0; i< n - 1; i++) for (int j = n - 1; i < j; j--) if (a[j] < a[j - 1]) swap(a[j], a[j - 1]); } // Driver Code int main() { int a[5] = { 10, 50, 30, 40, 20 }; int n = sizeof(a) / sizeof(a[0]); // calls template function bubbleSort (a, n); cout<< ' Sorted array : '; for (int i = 0; i < n; i++) cout << a[i] << ' '; cout << endl; return 0; }>
Вихід
Sorted array : 10 20 30 40 50>
Шаблони класів
Шаблони класів, такі як шаблони функцій, шаблони класів корисні, коли клас визначає щось, що не залежить від типу даних. Може бути корисним для таких класів, як LinkedList, BinaryTree, Stack, Queue, Array тощо.
приклад:
C++ // C++ Program to implement // template Array class #include using namespace std; template class Array { private: T* ptr; int розмір; public: Array(T arr[], int s); недійсний друк(); }; шаблонМасив::Array(T arr[], int s) { ptr = new T[s]; розмір = s; для (int i = 0; i< size; i++) ptr[i] = arr[i]; } template Масив void::print() { for (int i = 0; i< size; i++) cout << ' ' << *(ptr + i); cout << endl; } int main() { int arr[5] = { 1, 2, 3, 4, 5 }; Array a(arr, 5); a.print(); повернути 0; }>
Вихід
1 2 3 4 5>
Чи може бути більше ніж один аргумент для шаблонів?
Так, як і звичайні параметри, ми можемо передавати шаблонам більше ніж один тип даних як аргументи. Наступний приклад демонструє те саме.
приклад:
алгоритм kmpC++
// C++ Program to implement // Use of template #include using namespace std; template клас A { T x; U y; public: A() { cout<< 'Constructor Called' << endl; } }; int main() { Aa; А b; повернути 0; }>
Вихід
Constructor Called Constructor Called>
Чи можемо ми вказати значення за замовчуванням для аргументів шаблону?
Так, як і для звичайних параметрів, ми можемо вказати аргументи за замовчуванням для шаблонів. Наступний приклад демонструє те саме.
приклад:
C++ // C++ Program to implement // Use of template #include using namespace std; template клас A { public: T x; U y; A() { cout<< 'Constructor Called' << endl; } }; int main() { // This will call A Aa; повернути 0; }>
Вихід
Constructor Called>
Яка різниця між перевантаженням функцій і шаблонами?
І перевантаження функцій, і шаблони є прикладами особливостей поліморфізму ООП. Перевантаження функцій використовується, коли кілька функцій виконують досить подібні (не ідентичні) операції, шаблони використовуються, коли кілька функцій виконують ідентичні операції.
Що відбувається, коли в класі/функції шаблону є статичний член?
Кожен екземпляр шаблону містить власну статичну змінну. Побачити Шаблони та статичні змінні для більш детальної інформації.
Що таке спеціалізація шаблону?
Спеціалізація шаблону дозволяє нам мати різні коди для певного типу даних. Побачити Спеціалізація шаблону для більш детальної інформації.
Чи можемо ми передати нетипові параметри в шаблони?
Ми можемо передавати нетипові аргументи в шаблони. Нетипові параметри в основному використовуються для визначення максимальних чи мінімальних значень або будь-яких інших постійних значень для конкретного екземпляра шаблону. Важливо зауважити про нетипові параметри, що вони мають бути постійними. Компілятор повинен знати значення нетипових параметрів під час компіляції. Оскільки під час компіляції компілятору потрібно створити функції/класи для вказаного нетипового значення. У наведеній нижче програмі, якщо ми замінимо 10000 або 25 на змінну, ми отримаємо помилку компілятора.
приклад:
C++ // C++ program to demonstrate // working of non-type parameters // to templates in C++ #include using namespace std; template int arrMin(T arr[], int n) { int m = max; для (int i = 0; i< n; i++) if (arr[i] < m) m = arr[i]; return m; } int main() { int arr1[] = { 10, 20, 15, 12 }; int n1 = sizeof(arr1) / sizeof(arr1[0]); char arr2[] = { 1, 2, 3 }; int n2 = sizeof(arr2) / sizeof(arr2[0]); // Second template parameter // to arrMin must be a // constant cout << arrMin (arr1, n1)<< endl; cout << arrMin(arr2, n2); повернути 0; }>
Вихід
10 1>
Ось приклад програми C++ для відображення різних типів даних за допомогою конструктора та шаблону. Виконаємо кілька дій
- передача символьного значення шляхом створення об’єкта у функції main().
- передача цілого значення шляхом створення об’єкта у функції main().
- передача значення float шляхом створення об’єкта у функції main().
приклад:
C++ // C++ program to show different data types using a // constructor and template. #include using namespace std; // defining a class template template class info { public: // конструктор шаблону типу info(T A) { cout<< '
' << 'A = ' << A << ' size of data in bytes:' << sizeof(A); } // end of info() }; // end of class // Main Function int main() { // clrscr(); // passing character value by creating an objects infop('x'); // передача цілого значення шляхом створення інформації про об’єкт q(22); // передача значення float шляхом створення інформації про об’єктr(2,25); повернути 0; }>
Вихід
A = x size of data in bytes:1 A = 22 size of data in bytes:4 A = 2.25 size of data in bytes:4>
Вирахування аргументу шаблону
Дедукція аргументів шаблону автоматично виводить тип даних аргументу, переданого до шаблонів класу або функції. Це дозволяє нам створити екземпляр шаблону без явного вказівки типу даних.
Наприклад, розглянемо наведений нижче шаблон функції для множення двох чисел:
template t multiply (t num1,t num2) { return num1*num2; }>
Загалом, коли ми хочемо використовувати функцію multiply() для цілих чисел, ми повинні викликати її так:
multiply (25, 5);>
Але ми також можемо це назвати:
multiply(23, 5);>
Ми явно не вказуємо тип, тобто 1,3 є цілими числами.
Те саме стосується класів шаблонів (лише з C++17). Припустимо, ми визначаємо клас шаблону як:
template class student{ private: t total_marks; public: student(t x) : total_marks(x) {} };>
Якщо ми хочемо створити екземпляр цього класу, ми можемо використовувати будь-який із наступного синтаксису:
student stu1(23); or student stu2(24);>
Примітка: Важливо зазначити, що виведення аргументів шаблону для класів доступне лише з C++17, тому, якщо ми спробуємо використати автоматичне виведення аргументів шаблону для класу в попередній версії, це викличе помилку.
Приклад дедукції аргументу шаблону
Наведений нижче приклад демонструє, як векторний шаблон класу STL виводить тип даних, не вказуючи його явно.
C++ // C++ Program to illustrate template arguments deduction in // STL #include #include using namespace std; int main() { // creating a vector object without specifying // type vector v1{ 1.1, 2.0, 3.9, 4.909 }; cout << 'Elements of v1 : '; for (auto i : v1) { cout << i << ' '; } // creating a vector object without specifying type vector v2{ 1, 2, 3, 4 }; cout << endl << 'Elements of v2 : '; for (auto i : v2) { cout << i << ' '; } }>
Вихід
Elements of v1 : 1.1 2 3.9 4.909 Elements of v2 : 1 2 3 4>
Примітка: Наведена вище програма не зможе компілювати в C++14 і компіляторі нижче, оскільки в C++17 додано дедукцію аргументів шаблону класу.
Дедукція аргументів шаблону функції
Дедукція аргументів шаблону функції була частиною C++ з часів стандарту C++98. Ми можемо пропустити оголошення типу аргументів, які ми хочемо передати в шаблон функції, і компілятор автоматично виведе тип, використовуючи аргументи, які ми передали під час виклику функції.
приклад: У наступному прикладі ми демонструємо, як функції в C++ автоматично виводять свій тип самостійно.
C++ // C++ program to illustrate the function template argument // deduction #include using namespace std; // defining function template template t multiply(t first, t second) { return first * second; } // код драйвера int main() { auto result = multiply(10, 20); std::cout<< 'Multiplication OF 10 and 20: ' << result << std::endl; return 0; }>
Вихід
Multiplication OF 10 and 20: 200>
Примітка: Для шаблонів функцій, які мають однаковий тип для аргументів, як-от template void function(t a1, t a2){}, ми не можемо передати аргументи різних типів.
Дедукція аргументів шаблону класу (C++17 і далі)
Дедукція аргументу шаблону класу була додана в C++17 і з тих пір є частиною мови. Це дозволяє нам створювати екземпляри шаблонів класів без явного визначення типів, як шаблони функцій.
приклад: У наступному прикладі ми демонструємо, як компілятор автоматично класифікує шаблони в C++.
C++ // C++ Program to implement Class Template Arguments // Deduction #include #include #include using namespace std; // Defining class template template class student { private: string student_name; T total_marks; public: // Параметризований конструктор student(string n, T m) : student_name(n) , total_marks(m) { } void getinfo() { // друк деталей cout студента<< 'STUDENT NAME: ' << student_name << endl; cout << 'TOTAL MARKS: ' << total_marks << endl; cout << 'Type ID: ' << typeid(total_marks).name() << endl; } }; int main() { student s1('Vipul', 100); // Deduces student student s2('Yash', 98.5); // Deduces student s1.getinfo(); s2.getinfo(); return 0; }>
Вихід
STUDENT NAME: Vipul TOTAL MARKS: 100 Type ID: i STUDENT NAME: Yash TOTAL MARKS: 98.5 Type ID: d>
Тут i означає int, а d означає double.
Для шаблонного метапрограмування, r дивіться наступну статтю – Шаблонне метапрограмування .
Візьміть a Вікторина за шаблонами . Java також підтримує ці функції. Java називає це дженерики .