Специализация шаблонной функции




 

По сути, при использовании функции-шаблона используется механизм, по-зволяющий автоматически перегружать функции компилятором. Однако функ-цию-шаблон можно перегрузить и явно.

 

Если шаблонный алгоритм является неудовлетворительным для конкретного типа аргументов или неприменим к ним, то можно описать обычную функцию, список типов аргументов и возвращаемого значения которой соответствуют объ-явлению шаблона. Такая, перегружающая шаблон, функция, называется спе-циализацией шаблонной функции.

 

Следует отметить, что при обращении к функции-шаблону после имени функции можно и не указывать в угловых скобках фактические параметрические типы шаблона. В этом случае компилятор автоматически определяет фактические параметрические типы шаблона по типам фактических параметров вызова функ-ции. Это называется выведением типов аргументов шаблона. Выведение типов аргументов возможно при условии, что список фактических параметров вызова функции однозначно идентифицирует список параметров шаблона.

 

Так, описанную выше шаблонную функцию можно вызвать следующим об-разом:

 

int iarray[10];

 

int i_sum;

 

//...

 

i_sum = sum (iarray, 10);

 

Так как тип первого фактического параметра – int, то компилятор автома-тически трактует данный вызов, как

 

i_sum = sum < int > (iarray, 10);

 

Если параметр шаблона можно вывести из более, чем одного фактического параметра функции, результатом каждого выведения должен быть один и тот же тип. Иначе вызов будет ошибочным.

 

Пример:

 

template < class T> void f(T i, T* p){ /*... */ }

 

//...

void g(int i){

 

//...

f(i, &i); // правильный вызов

//...

// f(i,”helloworld”); - ошибка, т.к. по первому

// параметру T – int, по второму – constchar

 

}

 

Версия шаблона для конкретного набора фактических параметров шаблона также называется специализацией.

 

При выведении типов аргументов шаблона по типам фактических пара-метров функции нельзя применять никаких описанных выше преобразований параметров, кроме преобразований Точного отождествления, то есть:

 


Точное совпадение

 

• Совпадение с точностью до typedef

 

• Тривиальные преобразования:

 

 

T -> const T

 

Пример:

 

template < class T> T max(T t1, T t2){...} int main(){

max(1,2); // max<int>(1,2);
max(’a’,’b’); // max<char>(’a’,’b’);
max(2.7, 4.9); // max<double>(2.7, 4.9);
//max(’a’,1); // ошибка – неоднозначность,
  // стандартные преобразования не
//max(2.5,4); // допускаются
// ошибка – неоднозначность,
  // стандартные преобразования не
  // допускаются

}

 

Неоднозначности не возникают при использовании явного квалификатора:

 

max < int >(‘a’, 1);

 

max < double >(2.5, 4);

 

59. Контейнервектор

Контейнервектор

 

template < class T, class A = allocator <T>> сlass vector {

 

// vector – имя контейнера,

 

// T – тип элементов контейнера (value_type),

// A – распределитель памяти (allocator_type) –

 

необязательный параметр.

.......

public:

// Типы - typedef

 

//...

// Итераторы

//...

//

// Доступ к элементам:

//

reference operator [] (size_type n); // доступбез

 

// проверки

// диапазона

 

const_reference operator [] (size_type n) const; reference at(size_type n);

 

// доступ с проверкой диапазона (если индекс выходит за

 

// пределы диапазона, то возбуждается исключение

// out_of_range)

 

const_referenceat(size_type n) const;


 

reference front();


 

// первыйэлементвектора


 

const_referencefront()


 

const;


 

reference back();


 

// последнийэлементвектора


 

const_referenceback() const;

 

// Конструкторы:

 

//

// Конструкторы, которые могут вызываться с одним

// параметром, для предотвращения случайного

// преобразования объявлены explicit.

// Это означает, что конструктор может вызываться

// только явно:

// vector< int >v=10 - ошибка, попытка неявного

// преобразования числа 10 в vector< int >

 

explicit vector(const A&=A());

 

// конструктор умолчания – создается вектор нулевой

// длины

 

 


explicit vector(size_type n, const T& value = T(), const A& = A());

 

// создается вектор из n элементов со значением value

 

// (или со значениями типа Т, создаваемыми по умолчанию,

 

// если второй параметр отсутствует. В этом случае

// конструктор умолчания в классе Т – обязателен)

 

template < class I> vector (I first, I last,

 

const A& = A());

 

// I - итератор. Инициализация вектора копированием

 

// элемента, на который указывает итератор first, во все

 

// элементы из диапазона [first, last) (уже было

// отмечено, что функция end() возвращает итератор,

// который указывает на элемент, следующий за последним

 

// элементом).

 

vector(const vector < T, A >&obj);

 

// конструктор копирования

 

~vector(); // деструктор

 

//...

// Некоторые методы класса vector

//

vector& operator = (const vector < T, A >&obj);

 

bool empty () const {...} //истина, если контейнер пуст

 

size_type size () const {...} //выдачатекущегоразмера iterator insert (iterator i, const T& value) {...}

 

// вставка перед элементом

 

i
 

 

value res (на вставленный элемент)

 

iterator insert (iterator i, size_type number,

 

const T &value){...}

 

// вставка нескольких одинаковых элементов перед элементом

 

void push_back (cons t T&value) {insert(end(),value);}//вставкавконецконтейнера

 


void clear () {erase (begin(), end());}

 

// уничтожение всех элементов, при этом память не

// освобождается, так как деструктор самого вектора не

// вызывается

 

iterator erase (iterator i) {... return (res); }

 

// уничтожение заданного элемента и выдача итератора

// элемента, следующего за удалённым

i res

 

… …

 

 

iterator erase (iterator start, iterator finish)

 

// уничтожение диапазона [start,finish) и выдача

// итератора элемента, следующего за последним удалённым

 

{... return (finish);}

 

start finish = res

 

void pop_back () {erase (end() - 1); }

 

// уничтожение последнего элемента

 

referencefront () { return * begin (); }

 

// содержимое первого элемента

 

reference back () { return *(end () – 1); }

 

// содержимое последнего элемента

 

reference operator [](size_typei) {

 

return * (begin () + i); //индексациявектора

 

}

 

referenceat (size_t i) {... } // (аналог индексации) выдает // содержимое элемента i.

 

// Метод at() может возбудить

 

// исключение out_of_range.

 

}

 

Для организации поиска в контейнере в обратном порядке (от конца к на-чалу) обычно пишутся такие циклы:

 

template <class C> typename C::const_iterator find_last(

 

const C& c, typename C::value_type v){ typename C::const_iterator p = c.end ();

while (p!= c.begin ()) if (* -- p == v) return p; return c.end ();

 

}

 


 

Применив обратный итератор, можно воспользоваться библиотечной функцией поиска со всеми её преимуществами и без потери эффективности:

 

template <class C> typename C:: const_iteratorfind_last(

 

const C& c, typename C::value_type v)

{

typename C::const_reverse_iterator ri = find (c.rbegin (), c.rend (), v);

if (ri == c.rend ())

return c.end ();

 

typename C::const_iterator i = ri.base ();

 

return -- i;

 

}

 

Для обратного итератора выполнение операции ri.base() выдаёт значение типа iterator, указывающее на один элемент вперёд позиции, на которую указывает сам обратный итератор ri. Между итератором i и соответствующим обратным итератором существует фундаментальное отношение, выражающееся равенством

 

&*(reverse_iterator(i)) == &*(i - 1)

 

Операции insert() и erase() определены только для обычных итера-торов, поэтому организуя циклы по обратным итераторам, эти обратные итера-торы надо сначала преобразовывать к обычным, а лишь затем выполнять вставку или уничтожение элементов:

 

vector < int >:: reverse_iteratorri = v.rbegin (); while (ri!= v.rend ())

 

if (* ri ++ == Element){

vector< int >::iterator i = ri.base ();

 

v.insert (i, - Element); // передзаданным

// элементом

 

// вставить ещё один,

 

// с обратным знаком

 

break;

 

}

 

 


 

v.capacity()

 

  v.size()
vector v

past-the-end-element

 

 

элементы дополнительное пространство

 

v.rend()

 

v.begin() v.rbegin() v.end()

 

 




Поделиться:




Поиск по сайту

©2015-2024 poisk-ru.ru
Все права принадлежать их авторам. Данный сайт не претендует на авторства, а предоставляет бесплатное использование.
Дата создания страницы: 2018-01-31 Нарушение авторских прав и Нарушение персональных данных


Поиск по сайту: