2015-09-23 5 views
8

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

Например, если foo является {1, 3, 5, 7, 11}, то диапазоны 1-3, 3-5, 5-7, 7-11. Значительно для меня это соответствует 4 периодам. Обратите внимание, что каждый период включает в себя первое число в диапазоне, а не последнее. Поэтому в моем примере 8 появляется в третьем (нулевом) периоде. 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 не «заглядывает» очевидным образом.

+3

BTW, 'std :: distance (foo.begin(), std :: lower_bound (foo.begin(), foo.end(), bar)) - 1;' здесь более уместно. – Jarod42

ответ

9

В 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) 
5

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;}) 
+0

Что такое 'placeholders :: _ 1'? –

+0

Могли бы вы быть ангелом и собрать все это вместе? ;-) –

+0

@ P45Imminent буквально _placeholders_; см. [здесь] (http://www.cplusplus.com/reference/functional/placeholders/?kw=placeholders) –

8

Что о идти прямо из каменного века (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 как выражения. См. Lavevej's CppCon 2015 говорить.

+1

Я согласен, что это, вероятно, самое легкое для чтения решение, но теги вопроса включают только C++ 11. –

+0

@JasonR моя философия заключается в том, чтобы показать, как я буду ее кодировать, если они не утверждают, что они действительно не могут использовать C++ 14, и даже тогда я бы показал, если сбережения достаточно велики :) Q & A не просто для ОП, но для широкой общественности. Но я подтвердил ваш ответ 'bind' :) – TemplateRex

+0

достаточно честный; в этом есть смысл. +1. –

Смежные вопросы