Содержание
-
Шаблоны функций, специализация
Степанюк Константин Сергеевич 24const@gmail.com
-
Шаблоны функций
template void sort(vector&); void f (vector& vi, vector &vs){ sort(vi); //sort(vector&) sort(vs); //sort(vector&) } При вызове шаблона функции аргументы могут однозначно определять какая версия шаблона используется. В этом случае говорят что аргументы шаблона функции выводятся по аргументам функции Компилятор может вывести аргументы как являющиеся типами так и обычные при условии, что список аргументов функции однозначно идентифицирует набор аргументов шаблона
-
Пример
template T& lookup(Buffer&b, const char *p); class Record { const char[12]; //… }; Record& f(Buffer &buf, const char *p) { // вызвать lookup(), где T-Record, i -128 return lookup(buf,p); } //Иногда требуется указать аргумент явно: template T* create(); void f() { vector v; int *p = create(); }
-
Перегрузка шаблонов функций
template T sqrt(T); template complex sqrt( complex); double sqrt(double); void f(complex z){ sqrt(2); //sqrt (int) sqrt(2.0); //sqrt(double) sqrt(z);//sqrt (complex) }
-
Правила разрешения перегрузки
Ищется набор специализаций шаблонов функций, принимается решение какие аргументы были бы использованы, если бы в текущей области видимости не было других шаблонов функций и обычных функций с тем же именем (в примере –sqrt(complex) и sqrt>(complex) Если могут быть вызваны два шаблона функции и один из них более специализирован чем другой, на последующих этапах только он и рассматривается.(Для нашего примера предпочтение отдается sqrt(complex) по отношению к sqrt(complex) )
-
Разрешается перегрузка для данного набора функций, а также для любых обычных функций (в соответствии с правилами разрешения перегрузки для обычных функций). Если аргументы функции шаблона были определены путем выведения по фактическим аргументам шаблона, к ним нельзя применять «продвижение», стандартные и определяемые пользователем преобразования типа. (в нашем примере sqrt(int)является точным соответствием и поэтому ей отдается предпочтение по отношению к sqrt(double) Если и обычная функция и специализация подходят одинаково хорошо, то предпочтение отдается обычной функции (sqrt(double)а не sqrt(double)
-
Если ни одного соответствия не найдено или процесс оканчивается нахождением двух или более одинаково хорошо подходящими вариантами, то выдается соответствующая ошибка компиляции template T max (T, T); const int s = 7; void doIt() { max(1,2); // max(1,2) max('a','b'); // max('a','b') max(2.7,4.9); // max (2.7,4.9) max(s,7); //max(int(s), 7) –тривиальное преобр. max('a',1); //error –неоднозначность, стандартные //преобразования не применяются max(2.7,4); //error –неоднозначность }
-
Разрешение неоднозначности
Явная квалификация: max(‘a’,1); // max (int(‘a’), 1) max(2.7,4) // max(2.7, double(4)) Добавление подходящих объявлений inline int max (inti, int j) {return max(i, j);} inline double max (double d1, double d2) { return max(d1, d2); } inline double max (int i, double d) { return max(i, d);} inline double max (double d, int i) { return max(d, i);} void f () { max(‘a’,1); //max (int ('a'), 1) max(2.7, 4); //max (2.7, double (4)) }
-
Перегрузка и наследование
Правила перегрузки гарантируют, что функции шаблоны корректно взаимодействуют с наследованием: template class B {/*…*/}; template class D: public B {/*…*/}; template void f( B* ); void g (B *pb, D *pd) { f(pb); //f (pb) f(pd); //f (static_cast*>(pd)); }
-
Дополнительные аспекты разрешения
Аргумент функции, не использующийся при выведении параметра шаблона рассматривается точно также, как аргумент функции, не являющейся шаблоном, и к нему применяются обычные правила преобразования для аргумента функции при перегрузке обычных функций: template intget_nth (C& p, int n); class Index { public: operator int(); }; void f (vector &v, short s, Index i) { int i1 = get_nth (v, 2); //точное соответсвие int i2 = get_nth (v, s); //short в int int i3 = get_nth (v, i); //Index в int }
-
Использование аргументов шаблона для выведения алгоритма
template > int compare (const String& s1, const String& s2) { for (inti=0; i classCmp { public: static inteq (T a, T b) { return a==b; } static intlt (T a, T b) { return a str1, str2; //compare > (str1, str2); compare (str1,str2); compare > (wstr1, wstr2);
-
Специализация
По умолчанию шаблон предоставляет единое определение генерируемого типа которое используется для всех возможных аргументов шаблона Но иногда может возникнуть необходимость в уточнении определения для определенных категорий аргументов, например: «Если аргументом является указатель, то используй эту реализацию, если нет –используй ту» «Выдай сообщение об ошибке если аргументом шаблона не является указатель на объект класса, производного от My_base» Многие подобные проблемы решаются обеспечением альтернативных определений шаблона , выбор которых при инстанцировании осуществляет компилятор на основании аргументов шаблона указанных при его использовании
-
Класс Vector – кандидат на специализацию
template class Vector { T* v; intsz; public: Vector(); Vector(int); T& elem(inti) {return v[i];} T& operator[] (inti); void swap(Vector&); }; Vector vi; Vector vps; Vector vs; Vector vpc; Vector vpn;
-
Специализация Vector
template class Vector { void **p; intsz public: Vector(); Vector(int); void* &elem(inti) {return p[i];} void* &operator[] (inti) {return elem(i);} void swap(Vector&); //… }; Полная специализация –отсутствует параметр шаблона, который бы следовало задавать или который бы выводился при инстанцированиипри использовании специализации
-
Частичная специализация
template class Vector : private Vector { public: typedef Vector Base; Vector():Base() {} explicit Vector(int): Base(i) {} T* &elem(inti) { return static_cast (Base::elem()); } T* &operator[] (inti) { return static_cast (Base::operator[](i)); } //… }; Vector vps; // -это , T –shape Vector vppi; // -это , T –int*
-
Правила объявлений для специализаций
Общий шаблон должен быть объявлен прежде любой специализации Если программист специализирует где-нибудь шаблон, то эта специализация должна быть в области видимости при каждом использовании шаблона с типом, для которого он был специализирован Все специализации шаблона должны быть объявлены в том же пространстве имен что и сам шаблон Одна специализация считается более специализированной чем другая если каждый список аргументов соответствующий образцу первой специализации соответствует и второй специализации, но не наоборот Более специализированной версии будет отдаваться предпочтение в объявлениях объектов, указателей, а также при разрешении перегрузки
-
Пример, специализация функций
//общийшаблон template class Vector; //частичная специализация template class Vector; //полная специализация template class Vector; template bool less (T a, T b) {return a bool less (const char *a, const char *b) { return strcmp(a,b)можно опустить: template bool less(const char *a, const char *b) { return strcmp(a,b)
-
Наследование и шаблоны
Наследование реализации и обеспечение типобезопасного использования, например: template class Vector : private Vector{/*…*/}; Уточнение существующего шаблона (класса) или обобщение набора операций, например: template class CheckedVector : public Vector{/*…*/}; template class Basic_ops { public: bool operator==(const C&) const; bool operator!=(const C&) const; const C& derived() {return static_cast*this;} };
-
Пример использования
template class Math_container :public Basic_ops > { public: size_t size() const; T& operator[] (size_t); const T& operator[](size_t) const; //… }; template boolBasic_ops::operator==(const C& a) const { if (derived().size() != a.size()) return false; for (inti = 0; i
-
Организация исходного кода
Ранние компиляторы: Объявления и определения шаблонов размещаются в заголовочном файле Заголовочный файл включается во все единицы трансляции где используются данные шаблоны Современные компиляторы: Заголовочный файл включает только объявления шаблона, определение иго структуры и его специализаций (без определения членов шаблона) Определения членов шаблона размещаются в некоторой единице компиляции и предваряются ключевым словом export по аналогии со встраиваемыми (inline)функциями
-
Примеры кода
Первый вариант //file out.h : #include template void out (const T &t) {std::err void out (const T&); //file out.cpp #include export template void out(const T &t) {…} //file user2.cpp –отсутствует зависимость от iostream #include “out.h”
-
Вопросы
Какая лекция\тема понравилась Вам больше всего? Удовлетворяет ли Вас качество организации и проведения занятий? Как вы считаете, что следует изменить для улучшения качества усвоения материала? Планируете ли Вы в дальнейшем заниматься в сфере информационных технологий?
Нет комментариев для данной презентации
Помогите другим пользователям — будьте первым, кто поделится своим мнением об этой презентации.