自C++11以来,在算法库中,我们有all_of
、any_of
和none_of
来确定谓词是否适用于范围的所有元素、任何元素或无元素。对其中一个算法的单个调用返回1位信息,而对于特定的范围和谓词,有4种可能性:
- 谓词适用于所有元素,不适用于任何元素:范围为空
- 谓词适用于所有元素(范围不为空)
- 谓词不包含任何元素(并且范围不为空)
- 谓词包含某些元素,但不是所有元素
有没有一种简洁有效的方法可以找到这些信息?可以先调用all_of
,然后再调用none_of
,但(a)无法处理单程范围,(b)只对谓词求值一次。助推是可以接受的。
如果手动检查第一个元素并根据结果在all_of
或none_of
之间进行选择,则可以消除(a)和(b)两个问题。
代码(借用@Angew的enum
):
enum class Result {
empty, all, none, some
};
template <class FwIt, class Pred>
Result examine_range(FwIt from, FwIt to, Pred pred)
{
if (from == to) return Result::empty;
if (pred(*from)) {
++from;
return all_of(from,to,pred) ? Result::all : Result::some;
} else {
++from;
return none_of(from,to,pred) ? Result::none : Result::some;
}
}
我是错误地理解了这个问题,还是你可以通过std::accumulate
来做这件事?
using eana = std::tuple<bool, bool, bool, bool>;
template <typename T, typename FwdIt, typename Pred>
auto empty_all_none_any(FwdIt begin, FwdIt end, Pred predicate) -> eana {
auto result = eana{begin == end, begin != end, begin != end, false};
result = std::accumulate(begin, end, result, [&](eana& res, T& val) {
if (predicate(val)) {
std::get<2>(res) = false;
std::get<3>(res) = true;
}
else {
std::get<1>(res) = false;
}
return res;
});
return result;
}
这是我的首选算法(来自@Angew的枚举):
enum class Result {
empty, all, none, some
};
template<class InputIt, class UnaryPredicate>
Result examine_range(InputIt first, InputIt last, UnaryPredicate p)
{
bool all = true, none = true;
for (; first != last && (all || none); ++first)
(p(*first) ? none : all) = false;
return all ? (none ? Result::empty : Result::all)
: (none ? Result::none : Result::some);
}
您可以使用所描述的标准库函数来实现这一点。测试是否有任何元素为真,以及是否有元素为假,然后根据下表组合结果:
any true | none true
======================
any false | mixed | all false |
none false | all true | empty |