Использование std :: find_if () с функцией сравнения, которая принимает несколько входных параметров

Я пытаюсь использовать алгоритм std :: find_if() с функцией сравнения, которая принимает несколько входных аргументов, но я не уверен, как ее реализовать в моем коде. Я искал использование std :: find_if() на разных сайтах, но все они использовали функцию сравнения с одним входным аргументом.

using namespace std;

// comparison function
bool range_search(double x, double X1, double X2)
{
    return (x >= X1 && x <= X2) ? true : false;
}

// main   
vector x;

for(int i = 0; i < size; i++){
    x.push_back(...);
};

vector::iterator it = find_if(x.begin(), x.end(), range_search);
int pos_1 = distance(x.begin(), it);
1
Использовать объекты лямбда или функтора?
добавлено автор Some programmer dude, источник
Если вы посмотрите на cppreference , вы можете увидеть, что концепция предикатной функции UnaryPredicate . Таким образом, стандартная функция библиотеки будет принимать только функцию, которая принимает один аргумент и возвращает true/false. Ваша функция принимает 3 аргумента. Поэтому вам нужно обернуть его функцией, которая занимает всего одну.
добавлено автор Paul Rooney, источник
Можно ли использовать хотя бы стандарт C ++ 11?
добавлено автор Bob__, источник
константы X1 и X2?
добавлено автор P.W, источник
@ P.W да, X1 & X2 - константы. Но я хочу вызвать эту функцию пару раз. например X [2] [2] = {{1,2}, {3,4}}; для 1-го случая: X1 = X [0] [0], X2 = X [0] [1] и для второго случая X1 = X [1] [0], X2 = X [1] [1].
добавлено автор Ken, источник
@Bob__ Да, я могу использовать стандарт C ++ 11.
добавлено автор Ken, источник

5 ответы

Нет версии std :: find_if() , которая принимает предикат с несколькими входными аргументами. std :: find_if() выполняет итерацию через указанный диапазон итератора, передавая каждый элемент по одному в предикат. Таким образом, предикат должен принимать только один входной аргумент, не более, не менее. Вот почему все примеры, которые вы видели, используют 1 аргумент.

Функция range_search() , которую вы показали, просто несовместима для использования в качестве самого предиката.

В C ++ 11 и более поздних версиях вы можете использовать lambda для захвата дополнительных значений, которые вы хотите передать, в range_search() , например:

double X1 = ...;
doubke X2 = ...;
auto it = find_if(x.begin(), x.end(),
    [X1, X2](double x){ return range_search(x, X1, X2); }
);

До C ++ 11 вместо этого вы можете использовать объект-функтор:

struct range_search_s
{
    double X1, X2;
    range_search_s(double x1, double x2) : X1(x1), X2(x2) {}
    bool operator()(double x) { return range_search(x, X1, X2); }
};

double X1 = ...;
doubke X2 = ...;
vector::iterator it = find_if(x.begin(), x.end(), range_search_s(X1, X2));
4
добавлено

find_if requires only one argument to its test function because it has to test each element in the collection in turn. If you want to bind extra variables at call time, use a lambda:

double X1 = 2, X2 = 4;
auto it = find_if(x.begin(), x.end(),
                  [&](double v) { return (v >= X1 && v <= X2); });
3
добавлено
Thnx, он работает.
добавлено автор Ken, источник

Учитывая, что std :: find_if принимает только унарный предикат, вы можете построить его с помощью функции более высокого порядка с несколькими входными аргументами, возвращающими унарную лямбда:

#include 
#include 
#include 
#include 
#include 

namespace pred {

template 
constexpr auto is_in_range(const T min_value, const T max_value)
{
    return [min_value, max_value] (T x) { return x >= min_value && x <= max_value; };
}

}

int main()
{
    std::vector x {0.1, -3.0, 1.67, 4.0, 3.14, 1.5, 0.0, 2.0};

    auto it = find_if(x.begin(), x.end(), pred::is_in_range(1.0, 3.0));
    assert(distance(x.begin(), it) == 2  &&  *it == 1.67);  

    auto ranged = pred::is_in_range(0.0, 3.5);

    auto it2 = find_if(x.begin(), x.end(), ranged);   
    assert(distance(x.begin(), it2) == 0  &&  *it2 == 0.1);  

    std::vector y;
    std::copy_if(x.begin(), x.end(), std::back_inserter(y), ranged);
    assert(y.size() == 6);

    std::cout << "So far, so good...\n";
}
1
добавлено

Используйте лямбда:

vector:: iterator it = find_if(x.begin(),x.end(),[param1, param2, param3](const double& a, const double& b) { /* use param1-3 here*/ });
0
добавлено
Вы не можете использовать 2 значения параметров между () лямбда, find_if() будет принимать только 1 параметр.
добавлено автор Remy Lebeau, источник

Вы можете использовать std :: bind чтобы включить функцию с параметрами n в один с параметрами nx , предоставив некоторые аргументы в качестве констант:

auto fn = std::bind(&range_search, _1, 0.1, 0.9);

_1 является заполнителем для первого аргумента, который мы хотим сохранить переменной. Аргументы 0.1 и 0.9 передаются для параметров X1 и X2 соответственно.

Поскольку сгенерированная функция теперь имеет только один параметр, мы можем использовать ее с помощью std :: find_if() :

auto it = std::find_if(x.begin(), x.end(), fn);

Вы также можете объединить их в один вызов:

auto it = std::find_if(x.begin(), x.end(), std::bind(&range_search, _1, 0.1, 0.9));

Живая демонстрация в Coliru

0
добавлено
pro.cxx
pro.cxx
3 049 участник(ов)

C/C++ chat 0. Простые вопросы, лабы и о IDE — в чат новичков @supapro 1. Не хамим, не переходим на личности, не вбрасываем утверждения без доказательств 2. No Ads, offtop, flood Объявления о вакансиях и евенты - в лс @AlexFails https://t.me/ProCxx/259155

supapro.cxx
supapro.cxx
1 925 участник(ов)

Чат для тех, кто немного знает C++, простые вопросы по реализации, синтаксису и ide – сюда, а для другого есть: /Главный чат по серьезным вопросам — @ProCxx /Чат по обсуждению всего — @fludpac

C++ Russia
C++ Russia
384 участник(ов)

Сообщество разработчиков C++ в Telegram.

cxx.Дискуссионная
cxx.Дискуссионная
298 участник(ов)

это не двач, общайтесь вежливо; разговор на почти любые темы; Не согласны с баном? В лс @AlexFails, @ivario

C++ для маленьких и тупых
C++ для маленьких и тупых
105 участник(ов)

Лоу левел (по среднему IQ участников) чатик ExtremeCode @extremecode Флудилка @extremecode_rest