查找具有偶数值的向量元素

时间:2014-04-18 13:28:21

标签: c++ algorithm stl bind

您能解释一下这段代码的工作原理吗?它成功地计算了具有偶数值的向量元素,但是对于我来说这个特定情况下的绑定是如何工作的还不清楚。

count_if(vec.begin(), vec.end(),
         std::bind(logical_not<bool>(),
                   std::bind(modulus<int>(), placeholders::_1, 2)));

4 个答案:

答案 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)

在您的情况下,firstvec.begin()lastvec.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 objectlogical_not<bool>的输入。这只是否定了输入,例如如果输入为false(0),则logical_not<bool>会返回true,反之亦然。

因此,“计算标准”由此操作流程表示:

  1. 使用placeholders::_1 % 2计算:<<generic vector element>> % 2,即modulus
  2. 如果上述操作的结果为0(false),请使用true返回logical_not(反之亦然)。
  3. 所以,如果数字是偶数:

    1. even number % 2 == 0
    2. 否定0,你得到true
    3. 相反,如果数字是奇数:

      1. odd number % 2 == 1
      2. 否定1你得到false
      3. 由于count_if计算标准为true的元素数量,因此您计算了向量中的偶数数字。

        如果你真的想要计算向量中的奇数数字,你可以摆脱逻辑反转(即logical_not):

        auto odds = count_if(vec.begin(), vec.end(),
                             bind(modulus<int>(), placeholders::_1, 2));    
        

        请注意,在这种情况下,使用moduluslogical_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))

http://ideone.com/80VmsZ

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,以反转结果。