3719. Directory iterators should be usable with default sentinel

Section: 31.12.11.1 [fs.class.directory.iterator.general], 31.12.12.1 [fs.class.rec.dir.itr.general] Status: C++23 Submitter: Jonathan Wakely Opened: 2022-06-17 Last modified: 2024-01-29

Priority: Not Prioritized

View all issues with C++23 status.

Discussion:

We added comparisons with default_sentinel_t to the stream and streambuf iterators, because their past-the-end iterator is just a default-constructed iterator. We didn't do the same for filesystem directory iterators, but they also use a default-constructed value as the sentinel.

The proposed resolution addresses this oversight.

Previous resolution [SUPERSEDED]:

This wording is relative to N4910.

  1. Modify 31.12.11.1 [fs.class.directory.iterator.general], class directory_iterator synopsis, as indicated:

    namespace std::filesystem {
      class directory_iterator {
        […]
    
        const directory_entry& operator*() const;
        const directory_entry* operator->() const;
        directory_iterator& operator++();
        directory_iterator& increment(error_code& ec);
    
        friend bool operator==(const directory_iterator& lhs, default_sentinel_t) noexcept
        { return lhs == end(lhs); }
    
        // other members as required by 24.3.5.3 [input.iterators], input iterators
      };
    }
    
  2. Modify 31.12.12.1 [fs.class.rec.dir.itr.general], class recursive_directory_iterator synopsis, as indicated:

    namespace std::filesystem {
      class recursive_directory_iterator {
        […]
    
        void pop();
        void pop(error_code& ec);
        void disable_recursion_pending();
    
        friend bool operator==(const recursive_directory_iterator& lhs, default_sentinel_t) noexcept
        { return lhs == end(lhs); }
    
        // other members as required by 24.3.5.3 [input.iterators], input iterators
      };
    }
    

[2022-07-06; Jonathan Wakely revises proposed resolution and adds regex iterators as suggested on the reflector.]

[2022-07-11; Reflector poll]

Set status to Tentatively Ready after six votes in favour during reflector poll.

[2022-07-15; LWG telecon: move to Ready]

[2022-07-25 Approved at July 2022 virtual plenary. Status changed: Ready → WP.]

Proposed resolution:

This wording is relative to N4910.

  1. Modify 31.12.11.1 [fs.class.directory.iterator.general], class directory_iterator synopsis, as indicated:

    namespace std::filesystem {
      class directory_iterator {
        […]
    
        const directory_entry& operator*() const;
        const directory_entry* operator->() const;
        directory_iterator& operator++();
        directory_iterator& increment(error_code& ec);
    
        bool operator==(default_sentinel_t) const noexcept
        { return *this == directory_iterator(); }
    
        // other members as required by 24.3.5.3 [input.iterators], input iterators
      };
    }
    
  2. Modify 31.12.12.1 [fs.class.rec.dir.itr.general], class recursive_directory_iterator synopsis, as indicated:

    namespace std::filesystem {
      class recursive_directory_iterator {
        […]
    
        void pop();
        void pop(error_code& ec);
        void disable_recursion_pending();
    
        bool operator==(default_sentinel_t) const noexcept
        { return *this == recursive_directory_iterator(); }
    
        // other members as required by 24.3.5.3 [input.iterators], input iterators
      };
    }
    
  3. Modify 28.6.11.1.1 [re.regiter.general], regex_iterator synopsis, as indicated:

    namespace std {
      template<class BidirectionalIterator,
                class charT = typename iterator_traits<BidirectionalIterator>::value_type,
                class traits = regex_traits<charT>>
        class regex_iterator {
          […]
          regex_iterator& operator=(const regex_iterator&);
          bool operator==(const regex_iterator&) const;
          bool operator==(default_sentinel_t) const { return *this == regex_iterator(); }
          const value_type& operator*() const;
          const value_type* operator->() const;
    
  4. Modify 28.6.11.2.1 [re.tokiter.general], regex_token_iterator synopsis, as indicated:

    namespace std {
      template<class BidirectionalIterator,
                class charT = typename iterator_traits<BidirectionalIterator>::value_type,
                class traits = regex_traits<charT>>
        class regex_token_iterator {
          […]
          regex_iterator& operator=(const regex_token_iterator&);
          bool operator==(const regex_token_iterator&) const;
          bool operator==(default_sentinel_t) const { return *this == regex_token_iterator(); }
          const value_type& operator*() const;
          const value_type* operator->() const;