Search code examples
c++c++11bindbind2nd

A replacement for std::bind2nd


I have a foo which is a std::vector<int>. It represents the "edge" values for a set of ranges.

For example, if foo is {1, 3, 5, 7, 11} then the ranges are 1-3, 3-5, 5-7, 7-11. Significantly for me, this equates to 4 periods. Note that each period includes the first number in a range, and not the last one. So in my example, 8 appears in the 3rd (zero-based) period. 7 also appears in the 3rd period. 11 and above doesn't appear anywhere. 2 appears in the 0th period.

Given a bar which is an int, I use

std::find_if(
    foo.begin(),
    foo.end(),
    std::bind2nd(std::greater<int>(), bar)
) - foo().begin() - 1;

to give me the period that should contain bar.

My problem: std::bind2nd is deprecated so I ought to refactor. What is the equivalent statement using updated functions? std::bind doesn't "drop in" in the obvious way.


Solution

  • In C++11, you can use std::bind; it just isn't as obvious how to use it:

    #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;
    

    The key is the use of the placeholder argument, which are declared in the std::placeholders namespace. std::bind returns a function object that takes some number of parameters when it is invoked. The placeholders used inside the call to std::bind show how the arguments provided when the resulting object is invoked map to the argument list to the callable that you're binding to. So, for instance:

    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)