您能解释一下这段代码的工作原理吗?它成功地计算了具有偶数值的向量元素,但是对于我来说这个特定情况下的绑定是如何工作的还不清楚。
count_if(vec.begin(), vec.end(),
std::bind(logical_not<bool>(),
std::bind(modulus<int>(), placeholders::_1, 2)));
答案 0 :(得分:2)
从内部呼叫解析到外部呼叫:
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 )
计算迭代器定义的所有元素的cond(倒模数)./ / p>
placeholders::_1
是将count_if
(即当前元素)运行的迭代器驱动循环中确定的内容插入到嵌套在下面的函数中的硬连线方式。
答案 1 :(得分:2)
请注意,您发布的代码会计算向量中的偶数数字,不是奇数:
count_if(vec.begin(), vec.end(), bind(logical_not<bool>(), bind(modulus<int>(), placeholders::_1, 2)));
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
计算:<<generic vector element>> % 2
,即modulus
。0
(false),请使用true
返回logical_not
(反之亦然)。所以,如果数字是偶数:
even number % 2 == 0
true
。相反,如果数字是奇数:
odd number % 2 == 1
false
。由于count_if
计算标准为true
的元素数量,因此您计算了向量中的偶数数字。
如果你真的想要计算向量中的奇数数字,你可以摆脱逻辑反转(即logical_not
):
auto odds = count_if(vec.begin(), vec.end(),
bind(modulus<int>(), placeholders::_1, 2));
请注意,在这种情况下,使用modulus
和logical_not
的功能方法似乎过于复杂:使用 lambda (甚至是 ad hoc IsEven()
简单功能)会更清晰
考虑以下代码(live here on Ideone),以便在三种方法之间进行比较:
#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;
}
答案 2 :(得分:1)
这不计算奇数元素,但偶数元素。
要计算具有奇数值的向量元素,我们必须检查每个元素除以2,如果结果为1,则返回true。
因此我们将使用modulus(),它是一个实现operator()
的函数对象constexpr T operator()( const T& lhs, const T& rhs ) const;
并以rhs返回剩余的lhs除法。
我们必须使用std :: bind来粘合一个且只传递一个参数到
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
答案 3 :(得分:0)
这是一个双重绑定,首先计算modulus
乘以2的参数,这似乎相当于
y = x % 2
然后结果绑定到logical_not
,以反转结果。