`std::count_if` 的二进制谓词不起作用
Binary predicate for `std::count_if` is not working
我目前正在尝试使用 lambda 函数 std::count_if
数组中两个连续元素的总和等于一个数字。下面给出了示例代码。
#include <iostream>
#include <vector>
#include <algorithm>
int main()
{
const int Number = 3;
std::vector<int> vec = {1,1,2,4,5,6};
auto count = std::count_if( vec.begin(), vec.end(),
[&](int A, int B) -> bool
{ return A+B == Number; });
std::cout << count << '\n';
}
输出应该是 1
,因为我们有一种可能的情况(1 + 2
)。
但是,我无法成功。谁能告诉我我想念什么?
这是错误消息:
|234|error: no match for call to '(main()::<lambda(int, int)>) (int&)'|
问题是 std::count_if 使用了一元谓词。编译器告诉你什么:"You gave me a lambda with 2 arguments, I expected lambda with one argument"。
我相信你要找的是std::adjacent_find。它比较容器的每两个相邻元素(可能使用二元谓词)。
另一种可能的选择是使用 std::inner_product
。首先我会写一个小辅助函数:
#include <numeric>
#include <functional>
#include <iterator>
template <typename ForwardIterator, typename BinaryPredicate>
auto count_pairs_if(ForwardIterator first, ForwardIterator last,
BinaryPredicate pred)
{
const auto n = std::distance(first, last);
if (n < 2) return std::size_t {0};
return std::inner_product(first, std::next(first, n - 1), std::next(first),
std::size_t {0}, std::plus<> {}, pred);
}
template <typename Range, typename BinaryPredicate>
auto count_pairs_if(const Range& values, BinaryPredicate pred)
{
return count_pairs_if(std::cbegin(values), std::cend(values), pred);
}
然后你可以像这样使用它:
auto count = count_pairs_if(vec, [=] (auto lhs, auto rhs) { return lhs + rhs == Number; });
这里是 demo。
正如 @Yksisarvinen 所解释的那样,std::count_if
是为一元谓词设计的。所以编译器不能接受lambda,我通过了。
过了一段时间,我找到了解决这个问题的另一种方法。如果我提供一个模板函数,它需要
- 容器的迭代器(即开始和结束)(我需要对其进行相邻元素检查),以及
- 二元谓词,将用于检查相邻关系
这可能是一个更自然的解决方案,就像任何其他标准算法一样。 (See a live demo online)
template <typename Iterator, typename BinaryPred = std::equal_to<>>
constexpr std::size_t count_adjacent_if(
Iterator beginIter,
const Iterator endIter,
const BinaryPred pred = {})
{
if (beginIter == endIter) return 0; // nothing to do!
std::size_t count{};
for (Iterator nextIter{ beginIter }; ++nextIter != endIter; beginIter = nextIter)
if (pred(*beginIter, *nextIter))
++count;
return count;
}
可以这样称呼:
const auto count = ::count_adjacent_if(
vec.cbegin(), vec.cend(), [number](const int lhs, const int rhs) { return lhs + rhs == number; }
);
或点赞, let the predicate remember the previous element. Which is less recommended, since it is a non-generic solution and needs the non-empty container. (See a live demo online)
int lhs = vec[0];
const auto count = std::count_if(vec.cbegin() + 1, vec.cend(),
[&](const int rhs) {
const bool condition = (lhs + rhs == number); // check for the condition
lhs = rhs; // change the lhs = rhs (i.e. current element = next element)
return condition; // return the condition
});
我目前正在尝试使用 lambda 函数 std::count_if
数组中两个连续元素的总和等于一个数字。下面给出了示例代码。
#include <iostream>
#include <vector>
#include <algorithm>
int main()
{
const int Number = 3;
std::vector<int> vec = {1,1,2,4,5,6};
auto count = std::count_if( vec.begin(), vec.end(),
[&](int A, int B) -> bool
{ return A+B == Number; });
std::cout << count << '\n';
}
输出应该是 1
,因为我们有一种可能的情况(1 + 2
)。
但是,我无法成功。谁能告诉我我想念什么? 这是错误消息:
|234|error: no match for call to '(main()::<lambda(int, int)>) (int&)'|
问题是 std::count_if 使用了一元谓词。编译器告诉你什么:"You gave me a lambda with 2 arguments, I expected lambda with one argument"。
我相信你要找的是std::adjacent_find。它比较容器的每两个相邻元素(可能使用二元谓词)。
另一种可能的选择是使用 std::inner_product
。首先我会写一个小辅助函数:
#include <numeric>
#include <functional>
#include <iterator>
template <typename ForwardIterator, typename BinaryPredicate>
auto count_pairs_if(ForwardIterator first, ForwardIterator last,
BinaryPredicate pred)
{
const auto n = std::distance(first, last);
if (n < 2) return std::size_t {0};
return std::inner_product(first, std::next(first, n - 1), std::next(first),
std::size_t {0}, std::plus<> {}, pred);
}
template <typename Range, typename BinaryPredicate>
auto count_pairs_if(const Range& values, BinaryPredicate pred)
{
return count_pairs_if(std::cbegin(values), std::cend(values), pred);
}
然后你可以像这样使用它:
auto count = count_pairs_if(vec, [=] (auto lhs, auto rhs) { return lhs + rhs == Number; });
这里是 demo。
正如 @Yksisarvinen 所解释的那样,std::count_if
是为一元谓词设计的。所以编译器不能接受lambda,我通过了。
过了一段时间,我找到了解决这个问题的另一种方法。如果我提供一个模板函数,它需要
- 容器的迭代器(即开始和结束)(我需要对其进行相邻元素检查),以及
- 二元谓词,将用于检查相邻关系
这可能是一个更自然的解决方案,就像任何其他标准算法一样。 (See a live demo online)
template <typename Iterator, typename BinaryPred = std::equal_to<>>
constexpr std::size_t count_adjacent_if(
Iterator beginIter,
const Iterator endIter,
const BinaryPred pred = {})
{
if (beginIter == endIter) return 0; // nothing to do!
std::size_t count{};
for (Iterator nextIter{ beginIter }; ++nextIter != endIter; beginIter = nextIter)
if (pred(*beginIter, *nextIter))
++count;
return count;
}
可以这样称呼:
const auto count = ::count_adjacent_if(
vec.cbegin(), vec.cend(), [number](const int lhs, const int rhs) { return lhs + rhs == number; }
);
或点赞
int lhs = vec[0];
const auto count = std::count_if(vec.cbegin() + 1, vec.cend(),
[&](const int rhs) {
const bool condition = (lhs + rhs == number); // check for the condition
lhs = rhs; // change the lhs = rhs (i.e. current element = next element)
return condition; // return the condition
});