# std::ranges::empty

< cpp‎ | ranges

定义于头文件 `<ranges>` |  |
inline namespace /*unspecified*/ { inline constexpr auto empty = /*unspecified*/; } |  | (C++20 起) (定制点对象)
调用签名 |  |
template< class T > requires /* see below */ constexpr bool empty(T&& t); |  |

确定 `t` 是否拥有任何元素。

令 `t` 为 `T` 类型对象。对 `ranges::empty` 的调用表达式等价于：

1. bool(std::forward<T>(t).empty()) ，若该表达式合法。
2. 否则为 (ranges::size(std::forward<T>(t)) == 0) ，若该表达式合法。
3. 否则为 bool(ranges::begin(t) == ranges::end(t)) 。

所有其他情况下，对 `ranges::empty` 的调用非良构，这能在 ranges::empty(t) 出现于模板实例化的立即语境中时导致替换失败。

### 表达式等价

表达式 e 表达式等价于表达式 f ，若 e 与 f 拥有相同效果，均为潜在抛出或均非潜在抛出（即 noexcept(e) == noexcept(f) ），且均为常量子表达式或均非常量子表达式。

### 定制点对象

名字 `ranges::empty` 代表一个定制点对象，它是字面 `semiregular` 类类型的 const 函数对象。为说明目的，以 `__empty_fn` 表示其类型的 cv 无限定版本。

`__empty_fn` 的所有实例均相等。在相同参数上调用类型 `__empty_fn` 的不同实例的效果是等价的，无关乎指代该实例的表达式是左值还是右值，以及是否为 const 限定（然而不要求 volatile 限定的实例可调用）。从而能自由地复制 `ranges::empty` 并且能彼此替代地使用其副本。

给定类型集合 `Args...` ，若 std::declval<Args>()... 满足上面对于 `ranges::empty` 的参数要求，则 `__empty_fn` 实现 std::invocable<__empty_fn, Args...>、 std::invocable<const __empty_fn, Args...>、 std::invocable<__empty_fn&, Args...> 及 std::invocable<const __empty_fn&, Args...> 。否则， `__empty_fn` 的函数调用运算符不参与重载决议。

### 示例

    #include <iostream>
    #include <ranges>
    #include <vector>

    template <std::ranges::input_range R>
    void print(R&& r)
    {
        if (std::ranges::empty(r)) {
            std::cout << "\tEmpty\n";
            return;
        }

        std::cout << "\tElements:";
        for (const auto& element : r) {
            std::cout << ' ' << element;
        }

        std::cout << '\n';
    }

    int main()
    {
        {
            auto v = std::vector<int>{1, 2, 3};
            std::cout << "1. calling ranges::empty on std::vector:\n";
            print(v);

            v.clear();
            print(v);
        }
        {
            std::cout << "2. calling ranges::empty on std::initializer_list:\n";
            auto il = {7, 8, 9};
            print(il);

            print(std::initializer_list<int>{});
        }
        {
            std::cout << "2. calling ranges::empty on a raw array:\n";
            int array[] = {4, 5, 6}; // 数组拥有已知边界
            print(array);
        }
        {
            struct NoEmptyNorSize : private std::vector<int> {
                auto begin() { return std::vector<int>::begin(); }
                auto end() { return std::vector<int>::end(); }
            };

            std::cout << "3. calling ranges::empty on an object that satisfies only case 3):\n";
            print(NoEmptyNorSize{});
        }
    }

输出：

    1. calling ranges::empty on std::vector:
            Elements: 1 2 3
            Empty
    2. calling ranges::empty on std::initializer_list:
            Elements: 7 8 9
            Empty
    2. calling ranges::empty on a raw array:
            Elements: 4 5 6
    3. calling ranges::empty on an object that satisfies only case 3):
            Empty

### 参阅

empty (C++17) | 检查容器是否为空 (函数模板)