确定谓词是否适用于一个范围的全部、部分或全部元素



自C++11以来,在算法库中,我们有all_ofany_ofnone_of来确定谓词是否适用于范围的所有元素、任何元素或无元素。对其中一个算法的单个调用返回1位信息,而对于特定的范围和谓词,有4种可能性:

  • 谓词适用于所有元素,不适用于任何元素:范围为空
  • 谓词适用于所有元素(范围不为空)
  • 谓词不包含任何元素(并且范围不为空)
  • 谓词包含某些元素,但不是所有元素

有没有一种简洁有效的方法可以找到这些信息?可以先调用all_of,然后再调用none_of,但(a)无法处理单程范围,(b)只对谓词求值一次。助推是可以接受的。

如果手动检查第一个元素并根据结果在all_ofnone_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    |

最新更新