Namespaces
Variants
Views
Actions

Difference between revisions of "cpp/ranges/empty"

From cppreference.com
< cpp‎ | ranges
m
m ({{c}}, fmt)
 
(7 intermediate revisions by 4 users not shown)
Line 1: Line 1:
{{cpp/ranges/title | empty}}
+
{{cpp/ranges/title|empty}}
 
{{cpp/ranges/navbar}}
 
{{cpp/ranges/navbar}}
  
 
{{dcl begin}}
 
{{dcl begin}}
{{dcl header | ranges}}
+
{{dcl header|ranges}}
{{dcl header | iterator}}
+
{{dcl header|iterator}}
{{dcl | notes={{mark custpt}} | since=c++20 | 1=
+
{{dcl|notes={{mark custpt}}|since=c++20|1=
 
inline namespace /*unspecified*/ {
 
inline namespace /*unspecified*/ {
 
     inline constexpr auto empty = /*unspecified*/;
 
     inline constexpr auto empty = /*unspecified*/;
Line 11: Line 11:
 
}}
 
}}
 
{{dcl h|Call signature}}
 
{{dcl h|Call signature}}
{{dcl|1=
+
{{dcl|since=c++20|1=
 
template< class T >
 
template< class T >
 
     requires /* see below */
 
     requires /* see below */
constexpr bool empty(T&& t);
+
constexpr bool empty( T&& t );
 
}}
 
}}
 
{{dcl end}}
 
{{dcl end}}
  
Determines whether or not {{tt|t}} has any elements.
+
Determines whether or not {{c|t}} has any elements.
  
Let {{tt|t}} be an object of type {{tt|T}}. A call to {{tt|ranges::empty}} is expression-equivalent to:
+
A call to {{tt|ranges::empty}} is [[cpp/language/expressions#Expression-equivalence|expression-equivalent]] to:
# {{c|bool(std::forward<T>(t).empty())}}, if that expression is valid.
+
# {{c|bool(t.empty())}}, if that expression is valid.
# Otherwise, {{c|(ranges::size(std::forward<T>(t)) {{==}} 0)}}, if that expression is valid.
+
# Otherwise, {{c|1=(ranges::size(t) == 0)}}, if that expression is valid.
# Otherwise, {{c|bool(ranges::begin(t) {{==}} ranges::end(t))}}
+
# Otherwise, {{c|1=bool(ranges::begin(t) == ranges::end(t))}}, if that expression is valid and {{c|decltype(ranges::begin(t))}} models {{lc|std::forward_iterator}}.
  
 
In all other cases, a call to {{tt|ranges::empty}} is ill-formed, which can result in [[cpp/language/sfinae|substitution failure]] when {{c|ranges::empty(t)}} appears in the immediate context of a template instantiation.
 
In all other cases, a call to {{tt|ranges::empty}} is ill-formed, which can result in [[cpp/language/sfinae|substitution failure]] when {{c|ranges::empty(t)}} appears in the immediate context of a template instantiation.
  
{{cpp/expr-eq}}
 
 
{{cpp/ranges/cpo}}
 
{{cpp/ranges/cpo}}
  
 
===Example===
 
===Example===
 
{{example
 
{{example
|
+
|code=
| code=
+
 
#include <iostream>
 
#include <iostream>
 
#include <ranges>
 
#include <ranges>
 
#include <vector>
 
#include <vector>
  
template <std::ranges::input_range R>
+
template<std::ranges::input_range R>
void print(R&& r)
+
void print(char id, R&& r)
 
{
 
{
     if (std::ranges::empty(r)) {
+
     if (std::ranges::empty(r))
         std::cout << "\tEmpty\n";
+
    {
 +
         std::cout << '\t' << id << ") Empty\n";
 
         return;
 
         return;
 
     }
 
     }
  
     std::cout << "\tElements:";
+
     std::cout << '\t' << id << ") Elements:";
     for (const auto& element : r) {
+
     for (const auto& element : r)
 
         std::cout << ' ' << element;
 
         std::cout << ' ' << element;
    }
 
 
 
     std::cout << '\n';
 
     std::cout << '\n';
 
}
 
}
Line 58: Line 55:
 
     {
 
     {
 
         auto v = std::vector<int>{1, 2, 3};
 
         auto v = std::vector<int>{1, 2, 3};
         std::cout << "1. calling ranges::empty on std::vector:\n";
+
         std::cout << "(1) ranges::empty uses std::vector::empty:\n";
         print(v);
+
         print('a', v);
  
 
         v.clear();
 
         v.clear();
         print(v);
+
         print('b', v);
 
     }
 
     }
 
     {
 
     {
         std::cout << "2. calling ranges::empty on std::initializer_list:\n";
+
         std::cout << "(2) ranges::empty uses ranges::size(initializer_list):\n";
 
         auto il = {7, 8, 9};
 
         auto il = {7, 8, 9};
         print(il);
+
         print('a', il);
  
         print(std::initializer_list<int>{});
+
         print('b', std::initializer_list<int>{});
 
     }
 
     }
 
     {
 
     {
         std::cout << "3. calling ranges::empty on a raw array:\n";
+
         std::cout << "(2) ranges::empty on a raw array uses ranges::size:\n";
 
         int array[] = {4, 5, 6}; // array has a known bound
 
         int array[] = {4, 5, 6}; // array has a known bound
         print(array);
+
         print('a', array);
 +
    }
 +
    {
 +
        struct Scanty : private std::vector<int>
 +
        {
 +
            using std::vector<int>::begin;
 +
            using std::vector<int>::end;
 +
            using std::vector<int>::push_back;
 +
            // Note: both empty() and size() are hidden
 +
        };
 +
 
 +
        std::cout << "(3) calling ranges::empty on an object w/o empty() or size():\n";
 +
        Scanty y;
 +
        print('a', y);
 +
        y.push_back(42);
 +
        print('b', y);
 
     }
 
     }
 
}
 
}
 
|output=
 
|output=
1. calling ranges::empty on std::vector:
+
(1) ranges::empty uses std::vector::empty:
Elements: 1 2 3
+
        a) Elements: 1 2 3
Empty
+
        b) Empty
2. calling ranges::empty on std::initializer_list:
+
(2) ranges::empty uses ranges::size(initializer_list):
Elements: 7 8 9
+
        a) Elements: 7 8 9
Empty
+
        b) Empty
3. calling ranges::empty on a raw array:
+
(2) ranges::empty on a raw array uses ranges::size:
Elements: 4 5 6
+
        a) Elements: 4 5 6
 +
(3) calling ranges::empty on an object w/o empty() or size():
 +
        a) Empty
 +
        b) Elements: 42
 
}}
 
}}
  
 
===See also===
 
===See also===
 
{{dsc begin}}
 
{{dsc begin}}
{{dsc inc | cpp/iterator/dsc empty}}
+
{{dsc inc|cpp/iterator/dsc empty}}
 
{{dsc end}}
 
{{dsc end}}
  
 
{{langlinks|es|ja|zh}}
 
{{langlinks|es|ja|zh}}

Latest revision as of 10:26, 18 October 2023

 
 
Ranges library
Range adaptors
 
Defined in header <ranges>
Defined in header <iterator>
inline namespace /*unspecified*/ {

    inline constexpr auto empty = /*unspecified*/;

}
(since C++20)
(customization point object)
Call signature
template< class T >

    requires /* see below */

constexpr bool empty( T&& t );
(since C++20)

Determines whether or not t has any elements.

A call to ranges::empty is expression-equivalent to:

  1. bool(t.empty()), if that expression is valid.
  2. Otherwise, (ranges::size(t) == 0), if that expression is valid.
  3. Otherwise, bool(ranges::begin(t) == ranges::end(t)), if that expression is valid and decltype(ranges::begin(t)) models std::forward_iterator.

In all other cases, a call to ranges::empty is ill-formed, which can result in substitution failure when ranges::empty(t) appears in the immediate context of a template instantiation.

Customization point objects

The name ranges::empty denotes a customization point object, which is a const function object of a literal semiregular class type. For exposition purposes, the cv-unqualified version of its type is denoted as __empty_fn.

All instances of __empty_fn are equal. The effects of invoking different instances of type __empty_fn on the same arguments are equivalent, regardless of whether the expression denoting the instance is an lvalue or rvalue, and is const-qualified or not (however, a volatile-qualified instance is not required to be invocable). Thus, ranges::empty can be copied freely and its copies can be used interchangeably.

Given a set of types Args..., if std::declval<Args>()... meet the requirements for arguments to ranges::empty above, __empty_fn models

Otherwise, no function call operator of __empty_fn participates in overload resolution.

[edit] Example

#include <iostream>
#include <ranges>
#include <vector>
 
template<std::ranges::input_range R>
void print(char id, R&& r)
{
    if (std::ranges::empty(r))
    {
        std::cout << '\t' << id << ") Empty\n";
        return;
    }
 
    std::cout << '\t' << id << ") Elements:";
    for (const auto& element : r)
        std::cout << ' ' << element;
    std::cout << '\n';
}
 
int main()
{
    {
        auto v = std::vector<int>{1, 2, 3};
        std::cout << "(1) ranges::empty uses std::vector::empty:\n";
        print('a', v);
 
        v.clear();
        print('b', v);
    }
    {
        std::cout << "(2) ranges::empty uses ranges::size(initializer_list):\n";
        auto il = {7, 8, 9};
        print('a', il);
 
        print('b', std::initializer_list<int>{});
    }
    {
        std::cout << "(2) ranges::empty on a raw array uses ranges::size:\n";
        int array[] = {4, 5, 6}; // array has a known bound
        print('a', array);
    }
    {
        struct Scanty : private std::vector<int>
        {
            using std::vector<int>::begin;
            using std::vector<int>::end;
            using std::vector<int>::push_back;
            // Note: both empty() and size() are hidden
        };
 
        std::cout << "(3) calling ranges::empty on an object w/o empty() or size():\n";
        Scanty y;
        print('a', y);
        y.push_back(42);
        print('b', y);
    }
}

Output:

(1) ranges::empty uses std::vector::empty:
        a) Elements: 1 2 3
        b) Empty
(2) ranges::empty uses ranges::size(initializer_list):
        a) Elements: 7 8 9
        b) Empty
(2) ranges::empty on a raw array uses ranges::size:
        a) Elements: 4 5 6
(3) calling ranges::empty on an object w/o empty() or size():
        a) Empty
        b) Elements: 42

[edit] See also

(C++17)
checks whether the container is empty
(function template) [edit]