Категории
Самые читаемые
Лучшие книги » Компьютеры и Интернет » Программирование » Язык программирования C++. Пятое издание - Стенли Липпман

Язык программирования C++. Пятое издание - Стенли Липпман

Читать онлайн Язык программирования C++. Пятое издание - Стенли Липпман

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 222 223 224 225 226 227 228 229 230 ... 297
Перейти на страницу:

template <typename Т, typename F = less<T>>

int compare(const T &v1, const T &v2, F f = F()) {

 if (f(v1, v2)) return -1;

 if (f(v2, v1)) return 1;

 return 0;

}

Здесь в шаблон добавлен второй параметр типа, F, представляющий тип вызываемого объекта (см. раздел 10.3.2), и определен новый параметр функции, f, который будет связан с вызываемым объектом.

Предоставлено также значение по умолчанию для этого параметра шаблона и соответствующего ему параметра функции. Аргумент шаблона по умолчанию определяет, что функция compare() будет использовать библиотечный класс less объекта функции, экземпляр которого создается с тем же параметром типа, что и функция compare(). Заданный по умолчанию аргумент функции указывает, что параметр f будет инициализирован по умолчанию объектом типа F.

Когда пользователи вызывают эту версию функции compare(), они могут предоставить собственный оператор сравнения, но не обязаны делать это:

bool i = compare(0, 42); // использует less; i равно -1

// результат зависит от isbn в item1 и item2

Sales_data item1(cin), item2(cin);

bool j = compare(item1, item2, compareIsbn);

Первый вызов использует заданный по умолчанию аргумент функции, которым является объект типа less<T>. В этом вызове Т имеет тип int, поэтому у объекта будет тип less<int>. Этот экземпляр функции compare() будет использовать для сравнения тип less<int>.

Во втором вызове передается функция compareIsbn() (см. раздел 11.2.2) и два объекта типа Sales_data. Когда функция compare() вызывается с тремя аргументами, типом третьего аргумента должен быть вызываемый объект, возвращающий тип, приводимый к типу bool и получающий аргументы типа, совместимого с типами первых двух аргументов. Как обычно, типы параметров шаблона выводятся из соответствующих им аргументов функции. В этом вызове тип T выводится как тип Sales_data, а тип F — как тип compareIsbn().

Как и с аргументами функций по умолчанию, у параметра шаблона может быть аргумент по умолчанию, только если у всех параметров справа от него также есть аргументы по умолчанию.

Аргументы по умолчанию шаблона и шаблоны класса

Всякий раз, когда используется шаблон класса, за именем шаблона всегда должны следовать угловые скобки. Скобки означают, что класс будет создан как экземпляр шаблона. В частности, если шаблон класса предоставляет аргументы по умолчанию для всех своих параметров и следует использовать именно их, то после имени шаблона следует поместить пустую пару угловых скобок:

template <class Т = int> class Numbers { // по умолчанию Т - это int

public:

 Numbers(Т v = 0): val(v) { } // различные операции с числами

private:

 Т val;

};

Numbers<long double> lots_of_precision;

Numbers<> average_precision; // пустые <> означают тип по умолчанию

Здесь создаются два экземпляра шаблона Numbers: версия average_ precision — экземпляр Numbers с заменой параметра Т типом int; версия lots_of_precision — экземпляр Numbers с заменой параметра Т типом long double.

Упражнения раздела 16.1.3

Упражнение 16.17. Каковы (если есть) различия между параметром типа, объявленным с ключевым словом typename и ключевым словом class? Когда должно использоваться ключевое слово typename?

Упражнение 16.18. Объясните каждое из следующих объявлений шаблона функции и укажите, допустимы ли они. Исправьте все найденные ошибки.

(a) template <typename Т, U, typename V> void f1(T, U, V);

(b) template <typename T> T f2(int &T);

(c) inline template <typename T> T foo(T, unsigned int*);

(d) template <typename T> f4(T, T);

(e) typedef char Ctype;

     template <typename Ctype> Ctype f5(Ctype a);

Упражнение 16.19. Напишите функцию, получающую ссылку на контейнер и выводящую его элементы. Используйте переменную size_type и функцию-член size() контейнера для контроля цикла, вывода элементов.

Упражнение 16.20. Перепишите функцию из предыдущего упражнения так, чтобы использовать для контроля цикла итераторы, возвращаемые функциями begin() и end().

16.1.4. Шаблоны-члены

У класса (обычного или шаблона класса) может быть функция-член, которая сама является шаблоном. Такие члены называются шаблонами-членами (member template). Шаблоны-члены не могут быть виртуальными.

Шаблоны-члены обычных (не шаблонных) классов

В качестве примера обычного класса, у которого есть шаблон-член, определим класс, подобный стандартному типу функции удаления (deleter), используемой указателем unique_ptr (см. раздел 12.1.5). Как и у стандартной функции удаления, у данного класса будет перегруженный оператор вызова функции (см. раздел 14.8), который, получив указатель, выполняет для него оператор delete. В отличие от стандартной функции удаления, новый класс будет также выводить сообщения при каждом запуске. Поскольку создаваемую функцию удаления предстоит использовать с любым типом, сделаем оператор вызова шаблоном:

// класс объекта функции, вызывающий оператор delete для указателя

class DebugDelete {

public:

 DebugDelete(std::ostream &s = std::cerr): os(s) { }

 // подобно любым шаблонам функции, тип Т выводится компилятором

 template <typename Т> void operator()(Т *p) const

  { os << "deleting unique_ptr" << std::endl; delete p; }

private:

 std::ostream &os;

};

Как и любой другой шаблон, шаблон-член начинается с собственного списка параметров шаблона. У каждого объекта класса DebugDelete есть переменная-член типа ostream для вывода и функция-член, которая сама является шаблоном. Этот класс можно использовать вместо оператора delete:

double* p = new double;

DebugDelete d; // объект, способный действовать как оператор delete

d(p); // вызывает DebugDelete::operator()(double*), удаляющий p

int* ip = new int;

// вызывает operator()(int*) для временного объекта DebugDelete

DebugDelete()(ip);

Поскольку вызов объекта DebugDelete удаляет переданный ему указатель, его можно также использовать как функцию удаления для указателя unique_ptr. Чтобы переопределить функцию удаления указателя unique_ptr, укажем тип функции удаления в скобках и предоставим объект типа функции удаления конструктору (см. раздел 12.1.5):

// удалить объект, на который указывает p

// создает экземпляр DebugDelete::operator()<int>(int *)

unique_ptr<int, DebugDelete> p(new int, DebugDelete());

// удаляет объект, на который указывает sp

// создает экземпляр DebugDelete::operator()<string>(string*)

unique_ptr<string, DebugDelete> sp(new string, DebugDelete());

Здесь указано, что у функции удаления p будет тип DebugDelete и что предоставлен безымянный объект этого типа в конструкторе p().

Деструктор класса unique_ptr вызывает оператор вызова типа DebugDelete. Таким образом, при каждом вызове деструктора класса unique_ptr создается также экземпляр оператора вызова класса DebugDelete. Таким образом, определения выше создадут следующие экземпляры:

// примеры создания экземпляров шаблонов-членов DebugDelete

void DebugDelete::operator()(int *p) const { delete p; }

void DebugDelete::operator()(string *p) const { delete p; }

Шаблоны-члены шаблонов класса

Шаблон-член можно также определить и для шаблона класса. В данном случае у и класса, и у его члена будут собственные, независимые параметры шаблона.

В качестве примера снабдим класс Blob конструктором, который получает два итератора, обозначающих диапазон копируемых элементов. Поскольку желательно обеспечить поддержку итераторов в различных видах последовательностей, сделаем этот конструктор шаблоном:

template <typename Т> class Blob {

 template <typename It> Blob(It b, It e);

 // ...

};

У этого конструктора есть свой собственный параметр типа шаблона, It, который он использует для типа двух параметров функции.

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

template <typename Т>  // параметр типа для класса

template <typename It> // параметр типа для конструктора

1 ... 222 223 224 225 226 227 228 229 230 ... 297
Перейти на страницу:
На этой странице вы можете бесплатно скачать Язык программирования C++. Пятое издание - Стенли Липпман торрент бесплатно.
Комментарии