您能解释一下这段代码是如何工作的吗?它成功地计算了向量元素中偶数值的数量,但我不清楚在这种特定情况下绑定是如何工作的。
count_if(vec.begin(), vec.end(),
std::bind(logical_not<bool>(),
std::bind(modulus<int>(), placeholders::_1, 2)));
。
count_if(vec.begin(), vec.end(),
bind(logical_not<bool>(),
bind(modulus<int>(), placeholders::_1, 2)));
< p > count_if
是一个算法,它返回指定范围内满足特定条件的元素数量:
count_if(first, last, criteria)
first
是vec.begin()
,last
是vec.end()
:因此整个向量都被考虑在内。modulus<int>
是一个function object,它返回整数除法的余数(就像%
运算符)。它接受两个参数:第一个表示为placeholders::_1
,这是源向量中的通用元素。将其视为扫描整个向量内容的变量x
。2
,因为要检查整数是偶数还是奇数,可以计算x % 2
并将结果与0进行比较:x % 2 == 0 --> even number
x % 2 == 1 --> odd number
bind
用于指定 modulus
函数对象的参数。
这个模数运算的结果作为输入传递给另一个 function object: logical_not<bool>
,它只是对输入取反,例如如果输入是 false
(0),logical_not<bool>
返回 true
,反之亦然。
因此,“计数条件”由以下操作流程表示:
placeholders::_1 % 2
,即使用 modulus
计算 <<generic vector element>> % 2
。0
(false),则使用 logical_not
返回 true
(反之亦然)。因此,如果一个数字是偶数:
even number % 2 == 0
true
。如果一个数字是奇数:
奇数 % 2 == 1
false
。由于count_if
计算的是满足条件为true
的元素数量,因此你正在计算向量中的偶数数量。
如果你真的想计算向量中的奇数数量,你可以摆脱逻辑反转(即logical_not
):
auto odds = count_if(vec.begin(), vec.end(),
bind(modulus<int>(), placeholders::_1, 2));
#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;
}
从内部调用解开到外部调用:
modulus<int>( a, 2 )
返回除以2的余数:==0或!=0。
logical_not<bool>( x )
对x进行逻辑反转(因此0 / false变为1 / true,而1 / true变为0 / false)
count_if(from, to, cond )
placeholders::_1
是一种硬编码的方式,用于将迭代驱动循环运行中确定的某些内容(即当前元素)插入到下面嵌套的函数中。这不计算奇数元素,只计算偶数元素。
要计算具有奇数值的向量元素,我们必须检查每个元素是否可被2整除,并在结果为1时返回true。
因此,我们将使用modulus(),它是一个实现operator()的函数对象。
constexpr T operator()( const T& lhs, const T& rhs ) const;
count_if( InputIt first, InputIt last, UnaryPredicate p )
p
作为模数的第一个参数,常量 2
作为第二个参数。std::bind(modulus<int>(), placeholders::_1, 2))
std::bind(modulus<int>(), placeholders::_1, 2))
如果参数是奇数,则返回true(1),如果参数是偶数,则返回false(0)。如果我们想要计算偶数参数,我们必须忽略这个,因此我们的谓词必须返回相反的结果:std::bind(logical_not<bool>(),
std::bind(modulus<int>(), placeholders::_1, 2))
正如Mike Seymour建议的那样,更简单、更清晰的设计是用短lambda函数替换这些绑定。[](int x){return x % 2 == 0;} // to count even elements
[](int x){return x % 2 != 0;} // to count odds
这是一个双重绑定,首先计算参数的2的模数
,这似乎相当于
y = x % 2
然后将结果绑定到logical_not
,以反转结果。
var % 2
而不是 2 % var
。 - Ben Voigt
[](int x){return x % 2 != 0;}
替换那个混乱的代码。 - Mike Seymour