# std::ranges::is_partitioned

< cpp‎ | algorithm‎ | ranges

定义于头文件 `<algorithm>` |  |
调用签名 |  |
template< std::input_iterator I, std::sentinel_for<I> S, class Proj = std::identity, std::indirect_unary_predicate<std::projected<I, Proj>> Pred > constexpr bool is_partitioned( I first, S last, Pred pred, Proj proj = {} ); | (1) | (C++20 起)
template< ranges::input_range R, class Proj = std::identity, std::indirect_unary_predicate<std::projected<ranges::iterator_t<R>, Proj>> Pred > constexpr bool is_partitioned( R&& r, Pred pred, Proj proj = {} ); | (2) | (C++20 起)

1) 若范围 `[first, last)` 中在投影后满足谓词 `p` 的所有元素都在不满足的所有元素之前出现则返回 true 。若范围 `[first, last)` 为空则亦返回 true 。
2) 同 (1) ，但以 `r` 为源范围，如同以 ranges::begin(r) 为 `first` 并以 ranges::end(r) 为 `last` 。

此页面上描述的仿函数实体是 niebloid ，即：

- 调用它们中的任何一者时不可指定显式模板实参。
- 它们无一对实参依赖查找可见。
- 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

### 参数

first, last | - | 代表待检验的元素范围的迭代器-哨位对
r | - | 待检验的元素范围
pred | - | 应用到投影后元素的谓词
proj | - | 应用到谓词的投影

### 返回值

若 `[first, last)` 为空或为 `p` 所划分则为 true 。否则为 false 。

### 复杂度

至多应用 `ranges::distance(first, last)` 次 `pred` 和 `proj` 。

### 可能的实现

    struct is_partitioned_fn {
      template<std::input_iterator I, std::sentinel_for<I> S, class Proj = std::identity,
               std::indirect_unary_predicate<std::projected<I, Proj>> Pred>
      constexpr bool operator()(I first, S last, Pred pred, Proj proj = {}) const
      {
        for (; first != last; ++first) {
          if (!std::invoke(pred, std::invoke(proj, *first))) {
            break;
          }
        }

        for (; first != last; ++first) {
          if (std::invoke(pred, std::invoke(proj, *first))) {
            return false;
          }
        }

        return true;
      }

      template<ranges::input_range R, class Proj = std::identity,
               std::indirect_unary_predicate<std::projected<ranges::iterator_t<R>, Proj>> Pred>
      constexpr bool operator()(R&& r, Pred pred, Proj proj = {}) const
      {
        return (*this)(ranges::begin(r), ranges::end(r), std::ref(pred), std::ref(proj));
      }
    };

    inline constexpr auto is_partitioned = is_partitioned_fn();

### 示例

    #include <algorithm>
    #include <array>
    #include <iostream>
    #include <utility>

    int main()
    {
        std::array<int, 9> v;

        auto is_even = [](int i){ return i % 2 == 0; };
        auto print = [&](bool o) {
            for (int x : v) std::cout << x << ' ';
            std::cout << (o ? "=> " : "=> not ") << "partitioned\n";
        };

        std::iota(v.begin(), v.end(), 1);
        print(std::ranges::is_partitioned(v, is_even));

        std::ranges::partition(v, is_even);
        print(std::ranges::is_partitioned(std::as_const(v), is_even));

        std::ranges::reverse(v);
        print(std::ranges::is_partitioned(v.cbegin(), v.cend(), is_even));
        print(std::ranges::is_partitioned(v.crbegin(), v.crend(), is_even));
    }

输出：

    1 2 3 4 5 6 7 8 9 => not partitioned
    2 4 6 8 5 3 7 1 9 => partitioned
    9 1 7 3 5 8 6 4 2 => not partitioned
    9 1 7 3 5 8 6 4 2 => partitioned

### 参阅

ranges::partition (C++20) | 将范围中的元素分为二组 (niebloid)
ranges::partition_point (C++20) | 定位已划分范围的划分点 (niebloid)
is_partitioned (C++11) | 判断范围是否已按给定的谓词划分 (函数模板)