std::bind2nd and std::bind with bidimensional arra

2019-07-03 23:57发布

问题:

I know that C++ have lambdas and std::bind1st, std::bind2nd and std::bind are deprecated.

However, start with the foundations of C++, we can understand better new features.

So, I start with this very simple code, using an array of ints:

First example: with std::bind2nd

int array1[] = { 10, 20, 30, 40, 50, 60, 40 };
int c1, c2, c3;

c1 = count_if(array1, array1 + 7, bind2nd(greater<int>(), 40));
c2 = count_if(array1, array1 + 7, bind2nd(less<int>(), 40));
c3 = count_if(array1, array1 + 7, bind2nd(equal_to<int>(), 40));
cout << "There are " << c1 << " elements that are greater than 40." << endl;
cout << "There are " << c2 << " elements that are lesser than 40." << endl;
cout << "There are " << c3 << " elements that are equal to 40." << endl;

Second example: with std::bind

greater<int> big;
less<int> small;
equal_to<int> equal;

c1 = count_if(array1, array1 + 7, bind(big, _1, 40));
c2 = count_if(array1, array1 + 7, bind(small, _1, 40));
c3 = count_if(array1, array1 + 7, bind(equal, _1, 40));
cout << "There are " << c1 << " elements that are greater than 40." << endl;
cout << "There are " << c2 << " elements that are lesser than 40." << endl;
cout << "There are " << c3 << " elements that are equal to 40." << endl;

In both cases the output is:

There are 2 elements that are greater than 40.
There are 3 elements that are lesser than 40.
There are 2 elements that are equal to 40.

How can I do the same with bidimentional arrays like below:
(I want to made the same operations with the 2nd coordinate)

int array2[7][2] = { { 1, 10 }, { 2, 20 }, { 3, 30 }, 
                     { 4, 40 }, { 5, 50 }, { 6, 60 }, { 4, 40 } };

And with arrays of structs like this:

struct st
{
    char c;
    int i;
};

st array3[] = { { 'a', 10 }, { 'b', 20 }, { 'c', 30 }, 
                { 'd', 40 }, { 'e', 50 }, { 'f', 60 }, { 'd', 40 } };

In this case, I want to do the same operations with the field 'int' in the array of structs.

Can anyone help me?

Thank you

回答1:

bind1st, bind2nd and their brethren are deprecated in C++11 and outright removed in C++17. Just in case you didn't know this.

With bind, the solution is fairly straightforward, you can use the fact that bind expressions are composable and that you can use bind to extract a data member (placeholders omitted for brevity):

auto gr = count_if(array3, array3 + 7, bind(greater<>{}, bind(&st::i, _1), 40));
auto ls = count_if(array3, array3 + 7, bind(less<>{}, bind(&st::i, _1), 40));
auto eq = count_if(array3, array3 + 7, bind(equal_to<>{}, bind(&st::i, _1), 40));

With bind2nd it's not that easy. You need to declare a function object (can't use a function) that has several typedefs. You can use binary_function to ease this:

struct my_greater : binary_function<st, int, bool>
{
    bool operator()(st const& l, int r) const {
        return greater<>{}(l.i, r);
    }
};

Then you can call

auto old = count_if(array3, array3 + 7, bind2nd(my_greater{}, 40));

In C++11 you cam employ lambdas:

auto XI = count_if(array3, array3 + 7, [](st const& l){ return l.i > 40});

demo of all


If you have C++11 or newer available, it's almost always the better choice to use lambdas. It's not just a "good default", you'd have to really contort the situation for bind to be a better solution.