Замена для std :: bind2nd

у меня есть foo который является std::vector<int>, Он представляет «крайние» значения для набора диапазонов.

Например, если foo равен {1, 3, 5, 7, 11}, то диапазоны составляют 1-3, 3-5, 5-7, 7-11. Для меня это значимо 4 периода. Обратите внимание, что каждый период включает в себя первое число в диапазоне, а не последнее. Так что в моем примере 8 появляется в 3-м (нулевом) периоде. 7 также появляется в 3-м периоде. 11 и выше нигде не появляется. 2 появляется в 0-м периоде.

Учитывая bar который является int, Я использую

std::find_if(
foo.begin(),
foo.end(),
std::bind2nd(std::greater<int>(), bar)
) - foo().begin() - 1;

чтобы дать мне период, который должен содержать bar,

Моя проблема: std::bind2nd не рекомендуется, поэтому я должен рефакторинг. Что такое эквивалентное утверждение, использующее обновленные функции? std::bind не «заглядывает» очевидным образом.

10

Решение

В C ++ 11 вы можете использовать std::bind; просто не так очевидно, как его использовать:

#include <functional>
using namespace std::placeholders;
std::find_if(
foo.begin(),
foo.end(),
// create a unary function object that invokes greater<int>::operator()
// with the single parameter passed as the first argument and `bar`
// passed as the second argument
std::bind(std::greater<int>(), _1, bar)
) - foo().begin() - 1;

Ключом является использование аргумента заполнителя, который объявлен в std::placeholders Пространство имен. std::bind возвращает объект функции, который принимает некоторое количество параметров при вызове. Заполнители, используемые внутри вызова std::bind покажите, как аргументы, предоставляемые при вызове результирующего объекта, отображаются в списке аргументов для вызываемого объекта, к которому вы привязываетесь. Так, например:

auto op1 = std::bind(std::greater<int>(), _1, bar);
op1(5); // equivalent to std::greater<int>()(5, bar)

auto op2 = std::bind(std::greater<int>(), bar, _1);
op2(5); // equivalent to std::greater<int>()(bar, 5)

auto op3 = std::bind(std::greater<int>(), _2, _1);
op3(5, bar); // equivalent to std::greater<int>()(bar, 5)

auto op4 = std::bind(std::greater<int>(), _1, _2);
op4(5, bar); // equivalent to std::greater<int>()(5, bar)
11

Другие решения

Как насчет идти прямо из каменного века (bind2nd) к железному веку с общей лямбдой C ++ 14, минуя бронзовый век (bind)?

std::find_if(foo.begin(), foo.end(), [&](auto const& elem) {
return elem > bar;
});

И если вход отсортирован

std::lower_bound(foo.begin(), foo.end(), bar);

Лямбды читаются намного проще, и их легче встроить, чем std::bind . как выражения Смотрите, например CaveCon 2015 Лавевея говорить.

10

bind версия будет:

bind(std::greater<int>(), placeholders::_1, bar)

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

[bar](const int a){return bar < a;}

Также рекомендуется использовать перегруженные функции begin/end вместо вызовов методов. так было бы как:

find_if(begin(foo), end(foo), [bar](const int a){return bar < a;})
5