複数の入力パラメータをとる比較関数で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 そのため、標準ライブラリ関数は1つの引数を受け入れてtrue/falseを返す関数のみを受け入れます。あなたの関数は3つの引数を取ります。だからあなたはそれを1つだけ取る関数でそれをラップする必要があります。
追加された 著者 Paul Rooney,
あなたは少なくともC ++ 11標準を使うことを許されますか?
追加された 著者 Bob__,
X1とX2定数は何ですか?
追加された 著者 P.W,
@ P.Wはい、X1とX2は定数です。しかし、私はこの関数を2、3回呼び出したいと思います。例えばX [2] [2] = {{1,2}、{3,4}};第1の場合:X 1 = X [0] [0]、X 2 = X [0] [1]&第2の場合、X 1 = X [1] [0]、X 2 = X [1] [1]
追加された 著者 Ken,
@Bob__はい、私はC ++ 11標準を使うことができます。
追加された 著者 Ken,

5 答え

複数の入力引数を持つ述語を受け入れる 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より前のバージョンでは、代わりにFunctorオブジェクトを使用できます。

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.10.9 は、それぞれパラメーター X1X2 に渡されます。

生成された関数はただ一つのパラメータを持つようになったので、 std :: find_if()でそれを使うことができます。

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

2つを1つの呼び出しにまとめることもできます。

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

Coliruでのライブ

0
追加された