Лекция 23. Шаблоны (часть 3) презентация

Содержание


Презентации» Шаблоны, фоны презентаций» Лекция 23. Шаблоны (часть 3)
Лекция 23. Шаблоны (часть 3)
 Красс Александр
 Alexander.Krass@gmail.comТемы
 Частичная специализация
 Неполная специализация
 Шаблонные члены класса
 Шаблоны как параметрыЧастичная специализация
 Нам уже знакома полная специализация:
 template <typename T>
 classЧастичная специализация (2)
 А для чего еще можно выполнять частичную специализацию?Неполная специализация
 Неполная специализация позволяет нам указать часть параметров шаблона.
 templateШаблонные члены класса
 Иногда имеет смысл делать шаблонными не весь класс,Шаблонные члены класса (2)
 Вынесем стратегию управления памятью в отдельный класс:
Шаблонные члены класса (3)
 Теперь наш класс Array будет иметь следующийШаблоны как параметры шаблона
 Аргументами шаблона могут быть не только простыеФункциональные объекты
 Рассмотрим функцию find1, которая ищет указанное число в массивеФункциональные объекты (2)
 Обобщим нашу функцию find, добавив возможность поиска элементаФункциональные объекты (3)
 В итоге для реализации обобщенного поведения некоторой функцииФункциональные объекты (4)
 Тип с определенным оператором вызова функции называется функциональнымФункциональные объекты (5)
 После замены указателей на функциональные объекты и приведенияФункциональные объекты (6)
 Теперь мы можем использовать find3 следующим образом:
 ОпределимTraits
 Предположим, нам надо написать набор математических функций, работающих с разнымиTraits (2)
 Все эти величины для стандартных типов определены в файлеTraits (3)
 Определим обобщенный trait для всех типов:
 template <typename T>
Traits (4)
 Функция IsZero:
 template <typename T>
 bool IsZero(T val)
 {Спасибо за внимание
 Вопросы?



Слайды и текст этой презентации
Слайд 1
Описание слайда:
Лекция 23. Шаблоны (часть 3) Красс Александр Alexander.Krass@gmail.com


Слайд 2
Описание слайда:
Темы Частичная специализация Неполная специализация Шаблонные члены класса Шаблоны как параметры шаблона Функциональные объекты Traits

Слайд 3
Описание слайда:
Частичная специализация Нам уже знакома полная специализация: template <typename T> class vector { … }; template<> class vector<bool> { …}; Частичная специализация производится для подтипа: template <typename T> class vector<T*> { }; // специализация вектора для указателей. vector<T*> может проходить по своему содержимому и вызывать delete для каждого элемента. STL такой специализации нет.

Слайд 4
Описание слайда:
Частичная специализация (2) А для чего еще можно выполнять частичную специализацию?

Слайд 5
Описание слайда:
Неполная специализация Неполная специализация позволяет нам указать часть параметров шаблона. template <typename Data, typename Key> class Map {…}; Вариант Map для случая, когда ключ задается целым: template <typename Data> class Map<Data, int> {…}; Неполная специализация не нужна для шаблонных функций, т.к. там можно обойтись перегрузкой.

Слайд 6
Описание слайда:
Шаблонные члены класса Иногда имеет смысл делать шаблонными не весь класс, а отдельные методы. Рассмотрим шаблонный класс Array: template <typename T> class Array { … }; Array это динамический массив в стиле C++. Когда ему нужно перераспределить память, он вызывает оператор new, а когда удалить, оператор delete. Очевидно, что для разных случаев нужны разные стратегии управления памятью. (Пояснить?)

Слайд 7
Описание слайда:
Шаблонные члены класса (2) Вынесем стратегию управления памятью в отдельный класс: class StdMemoryMgr { public: template <typename T> static T* alloc(int n) { return new T[n]; } template <typename T> static void free(T *p) { delete[] p; } }; Реализуя разные версии этого класса, мы поддерживаем разные стратегии управления памятью. Например, вот так: class NoFreeMemoryMgr { public: template <typename T> static T* alloc(int n) { return new T[n]; } template <typename T> static void free(T *p) {} }; Класс NoFreeMemoryMgr можно использовать, если удаление очень дорого и оно нам не критично,

Слайд 8
Описание слайда:
Шаблонные члены класса (3) Теперь наш класс Array будет иметь следующий вид: template <typename T, typename Allocator = StdMemoryMgr> class Array { … }; Выделение памяти в классе будет производиться так: T* buf = Allocator::alloc<T>(size); Освобождение памяти так: Allocator::free<T>(buf);

Слайд 9
Описание слайда:
Шаблоны как параметры шаблона Аргументами шаблона могут быть не только простые типы, но и типы основанные на шаблонах К примеру, рассмотрим структуру данных стек. У него есть следующие операции: Push – помещаем элемент в стек Pop – удаляем элемент из стека Size – количество элементов в стеке Стек может быть реализован или на базе списка или на базе массива. Если мы автора класса Stack, мы не можем за пользователя решать, какую структуру нам использовать. Вынесем структуру в параметр шаблона template <class Type, class Container=Array<Type> > class Stack { void Push(const Type &v) { impl.push_back (v); } void Size() const { impl.size(); } … private: Container impl; }; Использование: Stack<int> si1; // стек на базе структуры данных по умолчанию (массива) Stack<int, List<int> > si2; // стек на базе списке. Обратите внимание на пробел между знаками >.

Слайд 10
Описание слайда:
Функциональные объекты Рассмотрим функцию find1, которая ищет указанное число в массиве типа int: const int* find1 ( const int* pool, int n, int x ) { const int* p = pool; for ( int i = 0; i<n; i++ ) { if ( *p == x ) return p; // success p++; } return 0; // fail } Пример использования: int A[100]; // заполнить A int* p = find1(A,100,5); // найти 5 в массиве

Слайд 11
Описание слайда:
Функциональные объекты (2) Обобщим нашу функцию find, добавив возможность поиска элемента по произвольному условию: const int* find2 ( const int* pool, int n, bool (*cond)(int) ) { const int* p = pool; for ( int i = 0; i<n; i++ ) { if ( cond(*p) ) return p; // success p++; } return 0; // fail } Пример использования: int A[100]; bool cond_e5 ( int x ) { return x==5; } int* p = find2(A,100,cond_e5); // найти элемент массива такой, что cond_e5(A[i]) равен true Другой пример такого дизайна функция qsort из стандартной библиотеки: void qsort ( void* base, // first element size_t num, // number of elements size_t width, // element size int (*compare)(const void*, const void*) ); // comparing function

Слайд 12
Описание слайда:
Функциональные объекты (3) В итоге для реализации обобщенного поведения некоторой функции нам надо передать в нее callback, который и будет выполнять настройку поведения этой функции Этот подход имеет и достоинства и недостатки: Механизм очень гибкий Низкая скорость из-за лишних вызовов функций. (Функции по указателю нельзя встроить) Хорошо бы сохранить гибкость callback и увеличить скорость. Воспользуемся помощью классов и шаблонов.

Слайд 13
Описание слайда:
Функциональные объекты (4) Тип с определенным оператором вызова функции называется функциональным типом. Функциональные типы делятся на встроенные и определяемые пользователем Указатель на функцию – это встроенный тип Класс с оператором вызова функции – определяемый пользователем

Слайд 14
Описание слайда:
Функциональные объекты (5) После замены указателей на функциональные объекты и приведения функции к шаблонному виду получим: template < typename T, typename Comparator > T* find3 ( T* pool, int n, Comparator comp ) { T* p = pool; for ( int i = 0; i<n; i++ ) { if ( comp(*p) ) return p; // success p++; } return 0; // fail } Новая версия имеет следующие преимущества: Ищет в массиве любого типа Ищет по любому критерию Она быстрее, чем find2, если оператор вызова функции встраивается.

Слайд 15
Описание слайда:
Функциональные объекты (6) Теперь мы можем использовать find3 следующим образом: Определим предикат поиска: template< typename T, T N> class less { public: bool operator()(T x) const { return x < N; } }; 2. Используем: int *p = find3(A, 100, less<int, 5>()); В STL есть аналогичная функция std::find и набор аналогичных предикатов на все случаи жизни.

Слайд 16
Описание слайда:
Traits Предположим, нам надо написать набор математических функций, работающих с разными типами данных: float, double, long double, плюс типы, определеяемые пользователем. При реализации этих функций нам хотелось бы знать о свойствах этих типов: Максимальное и минимальное значение Точность И пр. Реализация этих функций должна быть максимально обобщенной. Следовательно, используем шаблоны:

Слайд 17
Описание слайда:
Traits (2) Все эти величины для стандартных типов определены в файле float.h: /* Smallest value such that 1.0+xxx_EPSILON != 1.0 */ #define DBL_EPSILON 2.2204460492503131e-016 #define FLT_EPSILON 1.192092896e-07F #define LDBL_EPSILON 1.08420217248550443412e-019L /* max value */ #define DBL_MAX 1.7976931348623158e+308 #define FLT_MAX 3.402823466e+38F #define LDBL_MAX 1.189731495357231765e+4932L Но как организовать доступ к этим величинам из наших функций, в зависимости от типа аргументов? template <typename T> bool IsZero(T val) { return abs(val) < 10 * eps; } // eps – своя для каждого типа. Решение заключается в использовании Traits-ов

Слайд 18
Описание слайда:
Traits (3) Определим обобщенный trait для всех типов: template <typename T> class float_attrs { /* Пусто. Мы ничего не можем сказать про неизвестный тип. */};

Слайд 19
Описание слайда:
Traits (4) Функция IsZero: template <typename T> bool IsZero(T val) { return abs(val) < 10 * float_attrs<T>::epsilon(); } Использование: IsZero(1.f); // используем float_attrs<float> float_attrs это и есть трейтс, хранящий атрибуты чисел с плавающей запятой. Другое применение traits-ов это реализация стратегий, изменяющих поведение объекта.

Слайд 20
Описание слайда:
Спасибо за внимание Вопросы?


Скачать презентацию на тему Лекция 23. Шаблоны (часть 3) можно ниже:

Похожие презентации