質問

Say I have class A with member function int f() { return m_; } where m_ is a data member. I have a vector<A> called vec, and I want to find the object with maximum m_ value in vec using std::max_element. I can do it with a lambda:

auto cmp = [] (A& x, A& y) { return x.f() < y.f(); };
A& max_elem = *std::max_element(vec.begin(), vec.end(), cmp);

Is there some bind (or some such) trickery that will allow me to do it without a lambda and without defining my own comparator from scratch? Please don't suggest better ways to solve the max finding problem. It's only an example. The general question is how to wrap a function object that takes more than one argument (e.g., std::less<int>, which I would use as the comparator in the above example) in such a way that that arguments sent to it go through some other function (or member function) before getting to it.

役に立ちましたか?

解決

Yes, there is:

using namespace std::placeholders;
A& max = *std::max_element(begin(vec), end(vec)
    , std::bind(
        &std::less<int>::operator()
        , std::less<int>()
        , std::bind(&A::f, _1)
        , std::bind(&A::f, _2)
    )
);

Live example

However, if I ever saw this in code review, I'd immediately say "turn that ugliness into a lambda."


Thanks to @n.m. for poining out that the code can be shortened a bit:

using namespace std::placeholders;
A& max = *std::max_element(begin(vec), end(vec)
    , std::bind(
        std::less<int>()
        , std::bind(&A::f, _1)
        , std::bind(&A::f, _2)
    )
);

Live example

I still consider a lambda more readable, though. Bear in mind that you can use a lambda directly in the call to max_element() (no need for the variable cmp in your original code).

他のヒント

There's a number of ways you can supply a predicate to a algorithm. Below you'll see a number of examples of how this can be done. Here's a summary of the calls to std::max_element():

//here we're using an in-place lambda
A& max_elem = *std::max_element(vec.begin(), vec.end(), [](A& x, A&y){ return x.f() < y.f(); });
// here we're binding to a non-static member function
A& max_elem = *std::max_element(vec.begin(), vec.end(), std::bind(&A::compare, A(0), std::placeholders::_1, std::placeholders::_2));
// here we're binding to a non-member function
A& max_elem = *std::max_element(vec.begin(), vec.end(), std::bind(gcompare, std::placeholders::_1, std::placeholders::_2));
// here we're using the non-member function without using bind
A& max_elem = *std::max_element(vec.begin(), vec.end(), gcompare);

We could also use std::function.

Here's the full test source code so that you can play with it yourself:

class A
{
    int m_ = 0;
public:
    A(int max) : m_(max)
    {

    }
    A(const A& that)
    {
        m_ = that.m_;
    }
    A& operator=(const A& that)
    {
        m_ = that.m_;
    }
    int f() const
    {
        return m_;
    }
    bool compare(const A&x, const A&y) const
    {
        return x.m_ < y.m_;
    }
    static bool scompare(const A&x, const A&y)
    {
        return x.m_ < y.m_;
    }
};

static bool gcompare(const A&x, const A&y)
{
    return x.f() < y.f();
}

int main()
{
    std::vector<A> vec;
    vec.emplace_back(5);
    vec.emplace_back(7);
    vec.emplace_back(4);
    vec.emplace_back(9);
    vec.emplace_back(12);
    vec.emplace_back(1);


    A& max_elem = *std::max_element(vec.begin(), vec.end(), [](A& x, A&y){ return x.f() < y.f(); });
    A& max_elem = *std::max_element(vec.begin(), vec.end(), std::bind(&A::compare, A(0), std::placeholders::_1, std::placeholders::_2));
    A& max_elem = *std::max_element(vec.begin(), vec.end(), std::bind(gcompare, std::placeholders::_1, std::placeholders::_2));
    A& max_elem = *std::max_element(vec.begin(), vec.end(), gcompare);

}
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top