Note that the code you posted counts the even numbers in the vector, not the odd ones:
count_if(vec.begin(), vec.end(),
bind(logical_not<bool>(),
bind(modulus<int>(), placeholders::_1, 2)));
The count_if
is an algorithm that returns the number of elements in the specified range satisfying specific criteria:
count_if(first, last, criteria)
In your case, first
is vec.begin()
and last
is vec.end()
: so the whole vector is considered for the count.
Now let's focus the attention on the criteria part.
Starting from inner and going outer:
modulus<int>
is a function object that returns the remainder of an integer division (just like %
operator). It takes two arguments: the first is expressed as placeholders::_1
, which is the generic element in the source vector. Think of it as a variable x
that scans the entire vector content.
The second argument is the number 2
, since to check if an integer is even or odd, you can calculate x % 2
and compare the result with 0:
x % 2 == 0 --> even number
x % 2 == 1 --> odd number
bind
is used to specify the arguments of the modulus
function object.
The result of this modulus operation is given as input to another function object: logical_not<bool>
. This just negates the input, e.g. if the input was false
(0), logical_not<bool>
returns true
, and viceversa.
So, the "counting criteria" is expressed by this flow of operations:
- Calculate:
placeholders::_1 % 2
, i.e. <<generic vector element>> % 2
, using modulus
.
- If the result of the above operation is
0
(false), return true
(and viceversa), using logical_not
.
So, if a number is even:
even number % 2 == 0
- negating 0 you get
true
.
Instead, if a number is odd:
odd number % 2 == 1
- negating 1 you get
false
.
Since count_if
counts the number of elements for which the criteria is true
, you are counting the even numbers in the vector.
If you really want to count the odd numbers in the vector, you can just get rid of the logical inversion (i.e. logical_not
):
auto odds = count_if(vec.begin(), vec.end(),
bind(modulus<int>(), placeholders::_1, 2));
Note that in this case the functional approach using modulus
and logical_not
seems too complicated: using a lambda (or even an ad hoc IsEven()
simple function) would be clearer.
Consider the following code (live here on Ideone) for a comparison between the three approaches:
#include <algorithm>
#include <functional>
#include <iostream>
#include <vector>
using namespace std;
bool IsEven(int n) {
return (n % 2) == 0;
}
int main() {
// Test vector
vector<int> vec{ 11, 22, 33, 44, 55 };
// Using functional approach
auto n = count_if(vec.begin(), vec.end(),
bind(logical_not<bool>(),
bind(modulus<int>(), placeholders::_1, 2)));
cout << n << endl;
// Using lambdas
n = count_if(vec.begin(), vec.end(),
[](int n) { return (n % 2) == 0; });
cout << n << endl;
// Using boolean returning ad hoc function
n = count_if(vec.begin(), vec.end(), IsEven);
cout << n << endl;
}