The 
sub_match object stored at index 0 represents sub-expression 0,
i.e., the whole match
.  In this case the 
sub_match member
matched is always 
true.  The 
sub_match
object stored at index 
n denotes what matched the marked
sub-expression 
n within the matched expression
.  If the
sub-expression 
n participated in a regular expression
match then the 
sub_match member 
matched evaluates to 
true, and
members 
first and 
second denote the range of characters
[
first, second) which formed that
match
.  Otherwise 
matched is 
false, and members 
first
and 
second point to the end of the sequence
that was searched
.  [
Note 1: 
The 
sub_match objects representing
different sub-expressions that did not participate in a regular expression
match need not be distinct
. — 
end note]
namespace std {
  template<class BidirectionalIterator,
           class Allocator = allocator<sub_match<BidirectionalIterator>>>
    class match_results {
    public:
      using value_type      = sub_match<BidirectionalIterator>;
      using const_reference = const value_type&;
      using reference       = value_type&;
      using const_iterator  = implementation-defined;
      using iterator        = const_iterator;
      using difference_type =
              typename iterator_traits<BidirectionalIterator>::difference_type;
      using size_type       = typename allocator_traits<Allocator>::size_type;
      using allocator_type  = Allocator;
      using char_type       =
              typename iterator_traits<BidirectionalIterator>::value_type;
      using string_type     = basic_string<char_type>;
      
      match_results() : match_results(Allocator()) {}
      explicit match_results(const Allocator&);
      match_results(const match_results& m);
      match_results(match_results&& m) noexcept;
      match_results& operator=(const match_results& m);
      match_results& operator=(match_results&& m);
      ~match_results();
      
      bool ready() const;
      
      size_type size() const;
      size_type max_size() const;
      [[nodiscard]] bool empty() const;
      
      difference_type length(size_type sub = 0) const;
      difference_type position(size_type sub = 0) const;
      string_type str(size_type sub = 0) const;
      const_reference operator[](size_type n) const;
      const_reference prefix() const;
      const_reference suffix() const;
      const_iterator begin() const;
      const_iterator end() const;
      const_iterator cbegin() const;
      const_iterator cend() const;
      
      template<class OutputIter>
        OutputIter
          format(OutputIter out,
                 const char_type* fmt_first, const char_type* fmt_last,
                 regex_constants::match_flag_type flags = regex_constants::format_default) const;
      template<class OutputIter, class ST, class SA>
        OutputIter
          format(OutputIter out,
                 const basic_string<char_type, ST, SA>& fmt,
                 regex_constants::match_flag_type flags = regex_constants::format_default) const;
      template<class ST, class SA>
        basic_string<char_type, ST, SA>
          format(const basic_string<char_type, ST, SA>& fmt,
                 regex_constants::match_flag_type flags = regex_constants::format_default) const;
      string_type
        format(const char_type* fmt,
               regex_constants::match_flag_type flags = regex_constants::format_default) const;
      
      allocator_type get_allocator() const;
      
      void swap(match_results& that);
    };
}