Анимация
JavaScript
|
Главная Библионтека Объект функции, возвращенный алгоритмом for each(), присваивается mv, поэтому после вызова можно запросить информацию о его состоянии в виде mv.value(). В итоге программа выводит следующий результат: mean value: 4.5 Класс MeanValue можно дополнительно усоверщенствовать, определив автоматическое преобразование к типу double. В этом случае среднее арифметическое, вычисленное for each(), можно будет напрямую использовать в программе. Пример такого рода приведен на с. 335. Предикаты и объекты функций предикатом называется функция или объект функции, возвращающий логическое значение (или значение, преобразуемое к bool). Однако не каждая функция, возвращающая логическую величину, является предикатом по правилам STL. Иногда это приводит к весьма странным последствиям. Рассмотрим следующий пример: fo.removeif.срр finclude <1ostream> Unclude <l1st> finclude <algor1thrn> finclude "print.hpp" using namespace std; class Nth (, Объект функции возвращает true для n-го вызова private: int nth; Номер вызова, для которого следует вернуть true int count; Счетчик вызовов public: Nth (int n) : nth(n). count(O) ( } bool OperatorO (int) { return ++count == nth; int mainO ( 11st<1nt> col 1; Вставка элементов со значенияни от 1 до 9 for (int 1=1; i<=9; ++i) ( coll.push back(i): PRINT ELEMENTS(coll."coll: "): Удаление третьего элемента 11st<int>::1terator pos: pos = removejf(coll .beginO .col 1 .endO. Интервал Nth(3)): Критерий удаления coll .erase(pos.coll .endO); PRINT ELEMENTS(coll."nth removed: "): Программа определяет объект функции Nth, который возвращает true для каждого п-го вызова. Но если передать этот объект алгоритму removejf(), выполняющему удаление всех элементов, для которых унарный предикат возвращает true (см. с. 371), вас ждет сюрприз: coll: 12 3 4 5 6 7 8 9 nth removed: 12 4 5 7 8 9 Из коллекции удаляются два элемента, третий и шестой. Дело в том, что обычная реализация алгоритма создает внутреннюю копию предиката: template <class ForwIter. class Predlcate> Forwiter std::remove 1f(ForwIter beg, ForwIter end. Predicate op) beg = find if(beg. end. op): lf (beg == end) ( return beg; else ( ForwIter next = beg; return remove copy 1f(++next. end. beg. op); Для поиска первого удаляемого элемента алгоритм использует find if(), но затем для обработки оставшихся элементов используется копия переданного предиката ор. Объект функции Nth возвращается к прежнему состоянию и удаляет третий элемент из оставшихся (то есть шестой элемент коллекции). Такое поведение не является ошибкой. Стандарт не ограничивает внутреннее копирование предиката в алгоритме. Таким образом, для надежной работы алгоритмов стандартной библиотеки С++ не следует передавать объект функции, поведение которого зависит от частоты его копирования или вызова. Иначе говоря, если унарный предикат вызывается с одинаковыми аргументами, то он всегда должен возвращать один и тот же результат. Вызов не должен изменять внутреннее состояние предиката, а копия предиката должна иметь точно такое же состояние, как оригинал. Чтобы состояние предиката не изменялось при вызове функции, оператор () рекомендуется объявлять в виде чконстантной функции. В принципе это странное поведение можно обойти и обеспечить нормальную работу алгоритма даже с такими объектами функций, как Nth, без сниже- ния быстродействия. Для этого достаточно исключить из реализации remove if() вызов findjf(): template <class Forwlter. class Predicate> Forwiter std::remove 1f(Forwlter beg, Forwlter end, Predicate op) while Cbeg != end && !op(*beg)( ( ++beg: If Cbeg == end) ( return beg: else { Forwlter next = beg; return remove copy 1fC++next, end. beg. op); Вероятно, реализацию removeJf() стоило бы изменить (или подать заявку на ее изменение автору библиотеки). Насколько мне известно, в текущих реализациях эта проблема возникает только с алгоритмом removeJf(). Если использовать алгоритм remove copy if(), все работает нормально. Но если вы хотите, чтобы программа была действительно переносимой, никогда ие полагайтесь на особенности реализации. Всегда объявляйте оператор вызова функции и предикаты как константные функции классов. Стандартные объекты функций Как упоминалось на с. 140, стандартная библиотека С++ содержит ряд стандартных объектов функций. Эти объекты перечислены в табл. 8.1. Таблица 8.1. Стандартные объекты функций Выражение Описание
продолжение В настоящее время обсуждается вопрос о том, должна ли стандартная библиотека С++ гарантировать ожидаемое поведение в подобных случаях. В предыдущих версиях STL объект функции, выполнявший умножение, назывался times. Переимепование произошло из-за конфликта имен с функциями стандартов операционных систем (Х/Ореп, POSIX), а также потому, что идентификатор multiplies понятней. 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 [ 95 ] 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 |