Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
С++ Страуструп.doc
Скачиваний:
4
Добавлен:
18.04.2019
Размер:
2.72 Mб
Скачать

8.4.5 Введение операций с помощью параметров шаблонного класса

Возможны ситуации, когда неявность связи между шаблонной функцией

sort() и шаблонным классом Comparator создает трудности. Неявную

связь легко упустить из виду и в то же время разобраться в ней

может быть непросто. Кроме того, поскольку эта связь "встроена"

в функцию sort(), невозможно использовать эту функцию для

сортировки векторов одного типа, если операция сравнения рассчитана

на другой тип (см. упражнение 3 в $$8.9). Поместив функцию sort()

в класс, мы можем явно задавать связь с классом Comparator:

template<class T, class Comp> class Sort {

public:

static void sort(Vector<T>&);

};

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

использовать typedef в шаблоне Comparator:

template<class T> class Comparator {

public:

typedef T T; // определение Comparator<T>::T

static int lessthan(T& a, T& b) {

return a < b;

}

// ...

};

В специальном варианте для указателей на строки это определение

выглядит так:

class Comparator<char*> {

public:

typedef char* T;

static int lessthan(T a, T b) {

return strcmp(a,b) < 0;

}

// ...

};

После этих изменений можно убрать параметр, задающий тип элемента,

из класса Sort:

template<class T, class Comp> class Sort {

public:

static void sort(Vector<T>&);

};

Теперь можно использовать сортировку так:

void f(Vector<int>& vi,

Vector<String>& vc,

Vector<int>& vi2,

Vector<char*>& vs)

{

Sort< int,Comparator<int> >::sort(vi);

Sort< String,Comparator<String> >:sort(vc);

Sort< int,Comparator<int> >::sort(vi2);

Sort< char*,Comparator<char*> >::sort(vs);

}

и определить функцию sort() следующим образом:

template<class T, class Comp>

void Sort<T,Comp>::sort(Vector<T>& v)

{

for (int i=0; i<n-1; i++)

for (int j=n-1; i<j; j--)

if (Comp::lessthan(v[j],v[j-1])) {

T temp = v[j];

v[j] = v[j-1];

v[j-1] = temp;

}

}

Последний вариант ярко демонстрирует как можно соединять в одну

программу отдельные ее части. Этот пример можно еще больше

упростить, если использовать класс сравнителя (Comp) в качестве

единственного параметра шаблона. В этом случае в определениях класса

Sort и функции Sort::sort() тип элемента будет обозначаться как Comp::T.

8.5 Разрешение перегрузки для шаблонной функции

К параметрам шаблонной функции нельзя применять никаких преобразований

типа. Вместо этого при необходимости создаются новые варианты

функции:

template<class T> T sqrt(t);

void f(int i, double d, complex z)

{

complex z1 = sqrt(i); // sqrt(int)

complex z2 = sqrt(d); // sqrt(double)

complex z3 = sqrt(z); // sqrt(complex)

// ...

}

Здесь для всех трех типов параметров будет создаваться по шаблону

своя функция sqrt. Если пользователь захочет чего-нибудь иного,

например вызвать sqrt(double), задавая параметр int, нужно

использовать явное преобразование типа:

template<class T> T sqrt(T);

void f(int i, double d, complex z)

{

complex z1 = sqrt(double(i)); // sqrt(double)

complex z2 = sqrt(d); // sqrt(double)

complex z3 = sqrt(z); // sqrt(complex)

// ...

}

В этом примере по шаблону будут создаваться определения только для

sqrt(double) и sqrt(complex).

Шаблонная функция может перегружаться как простой, так и шаблонной

функцией того же имени. Разрешение перегрузки как шаблонных, так и

обычных функций с одинаковыми именами происходит за три шагаЬ:

Ь Эти правила слишком строгие, и, по всей видимости будут ослаблены,

чтобы разрешить преобразования ссылок и указателей, а, возможно,

и другие стандартные преобразования. Как обычно, при таких

преобразованиях будет действовать контроль однозначности.

[1] Найти функцию с точным сопоставлением параметров ($$R.13.2);

если такая есть, вызвать ее.

[2] Найти шаблон типа, по которому можно создать вызываемую

функцию с точным сопоставлением параметров; если такая есть,

вызвать ее.

[3] Попробовать правила разрешения для обычных функций ($$r13.2);

если функция найдена по этим правилам, вызвать ее, иначе

вызов является ошибкой.

В любом случае, если на первом шаге найдено более одной функции,

вызов считается неоднозначным и является ошибкой. Например:

template<class T>

T max(T a, T b) { return a>b?a:b; };

void f(int a, int b, char c, char d)

{

int m1 = max(a,b); // max(int,int)

char m2 = max(c,d); // max(char,char)

int m3 = max(a,c); // ошибка: невозможно

// создать max(int,char)

}

Поскольку до генерации функции по шаблону не применяется никаких

преобразований типа (правило [2]), последний вызов в этом

примере нельзя разрешить как max(a,int(c)). Это может сделать сам

пользователь, явно описав функцию max(int,int). Тогда вступает

в силу правило [3]:

template<class T>

T max(T a, T b) { return a>b?a:b; }

int max(int,int);

void f(int a, int b, char c, char d)

{

int m1 = max(a,b); // max(int,int)

char m2 = max(c,d); // max(char,char)

int m3 = max(a,c); // max(int,int)

}

Программисту не нужно давать определение функции max(int,int),

оно по умолчанию будет создано по шаблону.

Можно определить шаблон max так, чтобы сработал первоначальный

вариант нашего примера:

template<class T1, class T2>

T1 max(T1 a, T2 b) { return a>b?a:b; };

void f(int a, int b, char c, char d)

{

int m1 = max(a,b); // int max(int,int)

char m2 = max(c,d); // char max(char,char)

int m3 = max(a,c); // max(int,char)

}

Однако, в С и С++ правила для встроенных типов и операций над ними

таковы, что использовать подобный шаблон с двумя параметрами

может быть совсем непросто. Так, может оказаться неверно задавать

тип результата функции как первый параметр (T1), или, по крайней

мере, это может привести к неожиданному результату, например для

вызова

max(c,i); // char max(char,int)

Если в шаблоне для функции, которая

может иметь множество параметров с различными арифметическими

типами, используются два параметра, то в результате по шаблону будет

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

Более разумно добиваться преобразования типа, явно описав функцию

с нужными типами.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]