|
Программирование >> Разработка устойчивых систем
У этого решения имеется важное преимущество: оно работает и с узкими, и с расширенными потоками, поскольку базовый тип символов определяется параметром щаблона. Комитет по стандартизации С++ сейчас занимается такой модификацией языка, при которой бы работало самое первое решение (без преобразования типа), поэтому когда-нибудь об этих обходных решениях можно будет забыть. Применение функции к последовательным контейнерам STL Допустим, вы хотите вызвать некоторую функцию icnacca для всех объектов, хранящихся в последовательном контейнере STL (контейнеры STL рассматриваются в следующих главах, а пока воспользуемся знакомым контейнером vector). Поскольку vector может содержать объекты любого типа, вам понадобится функция, работающая с любой разновидностью vector: : C05:ApplySequence.h Применение функции к элементам последовательного контейнера STL Константная функция. О аргументов. произвольный тип возвращаемого значения: tempiate<class Seq, class T, class R> void apply(Seq& sq. R (T::*f)() const) { typename Seq::iterator it = sq.begin(): whiledt != sq.endO) { ((*it++)->*f)(): Константная функция. 1 аргумент. произвольный тип возвращаемого значения: tempiate<class Seq. class Т. class R. class A> void apply(Seq& sq. R(T::*f)(A) const. A a) { typename Seq: :iterator it = sq.beginO: whileCit != sq.endO) { ((*it++)->*f)(a): Константная функция. 2 аргумента. произвольный тип возвращаемого значения: tempiate<class Seq. class Т. class R. class Al. class A2> void apply(Seq& sq. R(T::*f)(Al. A2) const. Al al. A2 a2) { typename Seq::iterator it = sq.beginO: whileOt != sq.endO) { ((*it++)->*f)(al. a2): Неконстантная функция. О аргументов. произвольный тип возвращаемого значения: tempiate<class Seq. class Т. class R> void apply(Seq& sq. R (T::*f)()) { typename Seq: :iterator it = sq.beginO: while(it != sq.endO) { Неконстантная функция, 1 аргумент, произвольный тип возвращаемого значения: tempiate<class Seq. class Т. class R. class A> void apply(Seq& sq. R(T::*f)(A). A a) { typename Seq::iterator it - sq.beginO: while(it !- sq.endO) { ((*it++)->*f)(a): Неконстантная функция, 2 аргумента. произвольный тип возвращаемого значения: tempiate<class Seq, class Т. class R. class Al. class A2> void apply(Seq& sq. R(T::*f)(Al. A2). Al al. A2 a2) { typename Seq::iterator it - sq.beginO: while(it !- sq.endO) { ((*it++)->*f)(al. a2): И T. Д. для наиболее вероятных аргументов /:- Шаблон функции арр1у() получает ссылку на класс контейнера и указатель на функцию класса объектов, содержащихся в контейнере. Шаблон перебирает элементы контейнера при помощи итератора и вызывает функцию для каждого объекта. Мы перегрузили функции по константности, поэтому щаблон может использоваться как с константными, так и с неконстантными функциями. Обратите внимание: пример applySequence.h не включает заголовочные файлы STL (и вообще какие-либо заголовочные файлы), поэтому он не ограничивается контейнерами STL. С другой стороны, он делает определенные предположения, относящиеся к последовательным контейнерам STL (прежде всего по поводу имени и поведения iterator), а также считает, что элементы контейнера представляют собой указатели. Наличие нескольких версий арр1у() еще раз показывает, как перегружаются шаблоны функций. Хотя эти шаблоны позволяют использовать любой тип возвращаемого значения (который на самом деле игнорируется и требуется лишь для обязательного соответствия типов), разные версии получают разное число аргументов, а поскольку это шаблон, аргументы могут относиться к произвольному типу. Единственное неудобство состоит в том, что не существует супершаблона , который бы генерировал шаблоны за вас. Вы должны сами решить, сколько аргументов может понадобиться, и создать соответствующие определения. Чтобы проверить, как работают перегруженные версии арр1у(), мы создадим класс Gromit с функциями, получающими разное количество аргументов и возвращающих разные типы: Так зовут собаку, персонаж мультипликационных фильмов Ника Парка (Nick Park) о приключениях Уоллеса и Громита. ((*it++)->*f)(): : C05:Grom1t.h Киберсобака. Содержит несколько функций с разным количеством аргументов, linclude <iostream> class Gromit { 1nt arf: int total Barks: public: Gromitdnt arf = 1) : arf(arf + 1). totalBarks(O) {} void speak(int) { for(int i = 0: i < arf: i++) { std::cout arf! : ++totalBarks: std::COut Std::endl: char eat(float) const { std::cout chomp! std::endl: return z: int sleep(char, double) const { std::cout ill... std::endl: return 0: void sitO const { std::cout Sitting... std::endl: }: /:- Теперь мы можем воспользоваться шаблонными функциями арр1у() для применения функций класса Gromit к контейнеру vector<Gromit*>: : C05:ApplyGromit.cpp Тестирование ApplySequence.h linclude <cstddef> linclude <iostream> linclude <vector> linclude ApplySequence.h linclude Gromit.h linclude ../purge.h using namespace std: int mainO { vector<Gromit*> dogs: for(size t i = 0: i < 5: i++) dogs.push back(new Gromit(i)): apply(dogs. &Gromit::speak, 1): apply(dogs. &Gromit::eat, 2.Of): apply(dogs, &Gromit::sleep, z, 3.0); applyCdogs. &Gromit::sit); purge(dogs): } /:- Вспомогательная функция purge() вызывает delete для каждого элемента последовательного контейнера. Она определяется в главе 7 и используется во многих примерах книги. Определение арр1у() довольно запутанно; вряд ли неопытный программист сможет разобраться в нем. Но зато применение арр1у() выглядит крайне просто и оче-
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |