Читать «Стандарты программирования на С++. 101 правило и рекомендация» онлайн - страница 133
Андрей Александреску
data inserter(d, d.begin()), // в d с начала контейнера,
bind2nd(plus<double>(),41)); // добавляя к каждому 41
Впрочем, bind2nd
и plus
достаточно неудобны. Откровенно говоря, в действительности их мало кто использует, и связано это в первую очередь с плохой удобочитаемостью такого кода (см. рекомендацию 6).
При использовании лямбда-функций, генерирующих для нас функциональные объекты, мы можем написать совсем простой код:
transform(data, data+max, inserter(d,d.begin()), _1 + 41);
vector<int> v
первого элемента, значение которого находится между x
и y
. Он вычисляет итератор, который указывает либо на найденный элемент, либо на v.end()
:
vector<int>::iterator i = v.begin();
for (; i != v.end(); ++i)
if (*i > x && *i < y) break;
Вызов алгоритма достаточно проблематичен. При отсутствии лямбда-функций у нас есть два варианта — написание собственного функционального объекта или использование стандартных связывателей. Увы, в последнем случае мы не можем обойтись только стандартными связывателями и должны использовать нестандартный (хотя и достаточно распространенный) адаптер compose2
, но даже в этом случае код получается совершенно непонятным, так что такой код на практике никто просто не напишет:
vector<int>::iterator i =
find_if(v.begin(), v.end(),
compose2(logical_and<bool>(),
bind2nd(greater<int>(), x), bind2nd(less<int>(), y)));
Другой вариант, а именно — написание собственного функционального объекта — достаточно жизнеспособен. Он достаточно хорошо выглядит в точке вызова, а главный его недостаток— необходимость написания функционального объекта BetweenValues
, который визуально удаляет логику из точки вызова:
template<typename T>
class BetweenValues : public unary_function<T, bool> {
public:
BetweenValues(const T& low, const T& high)
: low_(low), high_(high) { }
bool operator()(const T& val) const
{ return val > low_ && val < high_; }
private:
T low_, high_;
};
vector<int>::iterator i =
find_if( v.begin(), v.end(), BetweenValues<int>(x, y));
При применении лямбда-функций можно написать просто:
vector<int>::iterator i =
find_if(v.begin(), v.end(), _1 > x && _1 < y);
Исключения
При использовании функциональных объектов тело цикла оказывается размещено в некотором месте, удаленном от точки вызова, что затрудняет чтение исходного текста. (Использование простых объектов со стандартными и нестандартными связывателями представляется нереалистичным.)
Лямбда-функции [Boost] решают проблему и надежно работают на современных компиляторах, но они не годятся для более старых компиляторов и могут выдавать большие запутанные сообщения об ошибках при некорректном использовании. Вызов же именованных функций, включая функции-члены, все равно требует синтаксиса с использованием связывателей.