Использование std :: find_if () с функцией сравнения, которая принимает несколько входных параметров - PullRequest
0 голосов
/ 27 сентября 2018

Я пытаюсь использовать алгоритм 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<double> x;

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

vector<double>::iterator it = find_if(x.begin(), x.end(), range_search);
int pos_1 = distance(x.begin(), it);

Ответы [ 5 ]

0 голосов
/ 27 сентября 2018

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

#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>
#include <cassert>

namespace pred {

template <class T>
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<double> 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<double> y;
    std::copy_if(x.begin(), x.end(), std::back_inserter(y), ranged);
    assert(y.size() == 6);

    std::cout << "So far, so good...\n";
}
0 голосов
/ 27 сентября 2018

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

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 голосов
/ 27 сентября 2018

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

double X1 = 2, X2 = 4;
auto it = find_if(x.begin(), x.end(),
                  [&](double v) { return (v >= X1 && v <= X2); });
0 голосов
/ 27 сентября 2018

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

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

В C ++ 11и позже вы можете использовать лямбду для захвата дополнительных значений, которые вы хотите передать 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<double>::iterator it = find_if(x.begin(), x.end(), range_search_s(X1, X2));
0 голосов
/ 27 сентября 2018

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

vector<double>:: iterator it = find_if(x.begin(),x.end(),[param1, param2, param3](const double& a, const double& b) { /* use param1-3 here*/ });
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...