This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of C++11 status.

1181. Invalid sub_match comparison operators

Section: 28.6.8.3 [re.submatch.op] Status: C++11 Submitter: Daniel Krügler Opened: 2009-07-25 Last modified: 2016-01-28

Priority: Not Prioritized

View all other issues in [re.submatch.op].

View all issues with C++11 status.

Discussion:

Several heterogeneous comparison operators of class template sub_match are specified by return clauses that are not valid in general. E.g. 28.6.8.3 [re.submatch.op]/7:

template <class BiIter, class ST, class SA>
bool operator==(
  const basic_string<
    typename iterator_traits<BiIter>::value_type, ST, SA>& lhs,
  const sub_match<BiIter>& rhs);

Returns: lhs == rhs.str().

The returns clause would be ill-formed for all cases where ST != std::char_traits<iterator_traits<BiIter>::value_type> or SA != std::allocator<iterator_traits<BiIter>::value_type>.

The generic character of the comparison was intended, so there are basically two approaches to fix the problem: The first one would define the semantics of the comparison using the traits class ST (The semantic of basic_string::compare is defined in terms of the compare function of the corresponding traits class), the second one would define the semantics of the comparison using the traits class

std::char_traits<iterator_traits<BiIter>::value_type>

which is essentially identical to

std::char_traits<sub_match<BiIter>::value_type>

I suggest to follow the second approach, because this emphasizes the central role of the sub_match object as part of the comparison and would also make sure that a sub_match comparison using some basic_string<char_t, ..> always is equivalent to a corresponding comparison with a string literal because of the existence of further overloads (beginning from 28.6.8.3 [re.submatch.op]/19). If users really want to take advantage of their own traits::compare, they can simply write a corresponding compare function that does so.

[ Post-Rapperswil ]

The following update is a result of the discussion during the Rapperswil meeting, the P/R expresses all comparisons by delegating to sub_match's compare functions. The processing is rather mechanical: Only == and < where defined by referring to sub_match's compare function, all remaining ones where replaced by the canonical definitions in terms of these two.

Moved to Tentatively Ready after 5 positive votes on c++std-lib.

[ Adopted at 2010-11 Batavia ]

Proposed resolution:

The wording refers to N3126.

  1. Change 28.9.2 [re.submatch.op]/7 as indicated:
    template <class BiIter, class ST, class SA>
     bool operator==(
       const basic_string<
         typename iterator_traits<BiIter>::value_type, ST, SA>& lhs,
       const sub_match<BiIter>& rhs);
    

    7 Returns: lhs == rhs.str()rhs.compare(lhs.c_str()) == 0.

  2. Change 28.9.2 [re.submatch.op]/8 as indicated:
    template <class BiIter, class ST, class SA>
     bool operator!=(
       const basic_string<
         typename iterator_traits<BiIter>::value_type, ST, SA>& lhs,
       const sub_match<BiIter>& rhs);
    

    8 Returns: lhs != rhs.str()!(lhs == rhs).

  3. Change 28.9.2 [re.submatch.op]/9 as indicated:
    template <class BiIter, class ST, class SA>
     bool operator<(
       const basic_string<
         typename iterator_traits<BiIter>::value_type, ST, SA>& lhs,
       const sub_match<BiIter>& rhs);
    

    9 Returns: lhs < rhs.str()rhs.compare(lhs.c_str()) > 0.

  4. Change 28.9.2 [re.submatch.op]/10 as indicated:
    template <class BiIter, class ST, class SA>
     bool operator>(
       const basic_string<
         typename iterator_traits<BiIter>::value_type, ST, SA>& lhs,
       const sub_match<BiIter>& rhs);
    

    10 Returns: lhs > rhs.str()rhs < lhs.

  5. Change 28.9.2 [re.submatch.op]/11 as indicated:
    template <class BiIter, class ST, class SA>
     bool operator>=(
       const basic_string<
       typename iterator_traits<BiIter>::value_type, ST, SA>& lhs,
     const sub_match<BiIter>& rhs);
    

    11 Returns: lhs >= rhs.str()!(lhs < rhs).

  6. Change 28.9.2 [re.submatch.op]/12 as indicated:
    template <class BiIter, class ST, class SA>
     bool operator<=(
       const basic_string<
         typename iterator_traits<BiIter>::value_type, ST, SA>& lhs,
       const sub_match<BiIter>& rhs);
    

    12 Returns: lhs <= rhs.str()!(rhs < lhs).

  7. Change 28.9.2 [re.submatch.op]/13 as indicated:
    template <class BiIter, class ST, class SA>
     bool operator==(const sub_match<BiIter>& lhs,
       const basic_string<
         typename iterator_traits<BiIter>::value_type, ST, SA>& rhs);
    

    13 Returns: lhs.str() == rhslhs.compare(rhs.c_str()) == 0.

  8. Change 28.9.2 [re.submatch.op]/14 as indicated:
    template <class BiIter, class ST, class SA>
     bool operator!=(const sub_match<BiIter>& lhs,
       const basic_string<
         typename iterator_traits<BiIter>::value_type, ST, SA>& rhs);
    

    14 Returns: lhs.str() != rhs!(lhs == rhs).

  9. Change 28.9.2 [re.submatch.op]/15 as indicated:
    template <class BiIter, class ST, class SA>
     bool operator<(const sub_match<BiIter>& lhs,
       const basic_string<
         typename iterator_traits<BiIter>::value_type, ST, SA>& rhs);
    

    15 Returns: lhs.str() < rhslhs.compare(rhs.c_str()) < 0.

  10. Change 28.9.2 [re.submatch.op]/16 as indicated:
    template <class BiIter, class ST, class SA>
     bool operator>(const sub_match<BiIter>& lhs,
       const basic_string<
         typename iterator_traits<BiIter>::value_type, ST, SA>& rhs);
    

    16 Returns: lhs.str() > rhsrhs < lhs.

  11. Change 28.9.2 [re.submatch.op]/17 as indicated:
    template <class BiIter, class ST, class SA>
     bool operator>=(const sub_match<BiIter>& lhs,
       const basic_string<
         typename iterator_traits<BiIter>::value_type, ST, SA>& rhs);
    

    17 Returns: lhs.str() >= rhs!(lhs < rhs).

  12. Change 28.9.2 [re.submatch.op]/18 as indicated:
    template <class BiIter, class ST, class SA>
     bool operator<=(const sub_match<BiIter>& lhs,
       const basic_string<
         typename iterator_traits<BiIter>::value_type, ST, SA>& rhs);
    

    18 Returns: lhs.str() <= rhs!(rhs < lhs).

  13. Change 28.9.2 [re.submatch.op]/19 as indicated:
    template <class BiIter>
     bool operator==(typename iterator_traits<BiIter>::value_type const* lhs,
       const sub_match<BiIter>& rhs);
    

    19 Returns: lhs == rhs.str()rhs.compare(lhs) == 0.

  14. Change 28.9.2 [re.submatch.op]/20 as indicated:
    template <class BiIter>
     bool operator!=(typename iterator_traits<BiIter>::value_type const* lhs,
       const sub_match<BiIter>& rhs);
    

    20 Returns: lhs != rhs.str()!(lhs == rhs).

  15. Change 28.9.2 [re.submatch.op]/21 as indicated:
    template <class BiIter>
     bool operator<(typename iterator_traits<BiIter>::value_type const* lhs,
       const sub_match<BiIter>& rhs);
    

    21 Returns: lhs < rhs.str()rhs.compare(lhs) > 0.

  16. Change 28.9.2 [re.submatch.op]/22 as indicated:
    template <class BiIter>
     bool operator>(typename iterator_traits<BiIter>::value_type const* lhs,
       const sub_match<BiIter>& rhs);
    

    22 Returns: lhs > rhs.str()rhs < lhs.

  17. Change 28.9.2 [re.submatch.op]/23 as indicated:
    template <class BiIter>
     bool operator>=(typename iterator_traits<BiIter>::value_type const* lhs,
       const sub_match<BiIter>& rhs);
    

    23 Returns: lhs >= rhs.str()!(lhs < rhs).

  18. Change 28.9.2 [re.submatch.op]/24 as indicated:
    template <class BiIter>
     bool operator<=(typename iterator_traits<BiIter>::value_type const* lhs,
       const sub_match<BiIter>& rhs);
    

    24 Returns: lhs <= rhs.str()!(rhs < lhs).

  19. Change 28.9.2 [re.submatch.op]/25 as indicated:
    template <class BiIter>
     bool operator==(const sub_match<BiIter>& lhs,
       typename iterator_traits<BiIter>::value_type const* rhs);
    

    25 Returns: lhs.str() == rhslhs.compare(rhs) == 0.

  20. Change 28.9.2 [re.submatch.op]/26 as indicated:
    template <class BiIter>
     bool operator!=(const sub_match<BiIter>& lhs,
       typename iterator_traits<BiIter>::value_type const* rhs);
    

    26 Returns: lhs.str() != rhs!(lhs == rhs).

  21. Change 28.9.2 [re.submatch.op]/27 as indicated:
    template <class BiIter>
     bool operator<(const sub_match<BiIter>& lhs,
       typename iterator_traits<BiIter>::value_type const* rhs);
    

    27 Returns: lhs.str() < rhslhs.compare(rhs) < 0.

  22. Change 28.9.2 [re.submatch.op]/28 as indicated:
    template <class BiIter>
     bool operator>(const sub_match<BiIter>& lhs,
       typename iterator_traits<BiIter>::value_type const* rhs);
    

    28 Returns: lhs.str() > rhsrhs < lhs.

  23. Change 28.9.2 [re.submatch.op]/29 as indicated:
    template <class BiIter>
     bool operator>=(const sub_match<BiIter>& lhs,
       typename iterator_traits<BiIter>::value_type const* rhs);
    

    29 Returns: lhs.str() >= rhs!(lhs < rhs).

  24. Change 28.9.2 [re.submatch.op]/30 as indicated:
    template <class BiIter>
     bool operator<=(const sub_match<BiIter>& lhs,
       typename iterator_traits<BiIter>::value_type const* rhs);
    

    30 Returns: lhs.str() <= rhs!(rhs < lhs).

  25. Change 28.9.2 [re.submatch.op]/31 as indicated:
    template <class BiIter>
     bool operator==(typename iterator_traits<BiIter>::value_type const& lhs,
       const sub_match<BiIter>& rhs);
    

    31 Returns: basic_string<typename iterator_traits<BiIter>::value_type>(1, lhs) == rhs.str().
    31 Returns: rhs.compare(typename sub_match<BiIter>::string_type(1, lhs)) == 0.

  26. Change 28.9.2 [re.submatch.op]/32 as indicated:
    template <class BiIter>
     bool operator!=(typename iterator_traits<BiIter>::value_type const& lhs,
       const sub_match<BiIter>& rhs);
    

    32 Returns: basic_string<typename iterator_traits<BiIter>::value_type>(1, lhs) != rhs.str()!(lhs == rhs).

  27. Change 28.9.2 [re.submatch.op]/33 as indicated:
    template <class BiIter>
     bool operator<(typename iterator_traits<BiIter>::value_type const& lhs,
       const sub_match<BiIter>& rhs);
    

    33 Returns: basic_string<typename iterator_traits<BiIter>::value_type>(1, lhs) < rhs.str().
    33 Returns: rhs.compare(typename sub_match<BiIter>::string_type(1, lhs)) > 0.

  28. Change 28.9.2 [re.submatch.op]/34 as indicated:
    template <class BiIter>
     bool operator>(typename iterator_traits<BiIter>::value_type const& lhs,
       const sub_match<BiIter>& rhs);
    

    34 Returns: basic_string<typename iterator_traits<BiIter>::value_type>(1, lhs) > rhs.str()rhs < lhs.

  29. Change 28.9.2 [re.submatch.op]/35 as indicated:
    template <class BiIter>
     bool operator>=(typename iterator_traits<BiIter>::value_type const& lhs,
       const sub_match<BiIter>& rhs);
    

    35 Returns: basic_string<typename iterator_traits<BiIter>::value_type>(1, lhs) >= rhs.str()!(lhs < rhs).

  30. Change 28.9.2 [re.submatch.op]/36 as indicated:
    template <class BiIter>
     bool operator<=(typename iterator_traits<BiIter>::value_type const& lhs,
       const sub_match<BiIter>& rhs);
    

    36 Returns: basic_string<typename iterator_traits<BiIter>::value_type>(1, lhs) <= rhs.str()!(rhs < lhs).

  31. Change 28.9.2 [re.submatch.op]/37 as indicated:
    template <class BiIter>
     bool operator==(const sub_match<BiIter>& lhs,
       typename iterator_traits<BiIter>::value_type const& rhs);
    

    37 Returns: lhs.str() == basic_string<typename iterator_traits<BiIter>::value_type>(1, rhs).
    37 Returns: lhs.compare(typename sub_match<BiIter>::string_type(1, rhs)) == 0.

  32. Change 28.9.2 [re.submatch.op]/38 as indicated:
    template <class BiIter>
     bool operator!=(const sub_match<BiIter>& lhs,
       typename iterator_traits<BiIter>::value_type const& rhs);
    

    38 Returns: lhs.str() != basic_string<typename iterator_traits<BiIter>::value_type>(1, rhs)!(lhs == rhs).

  33. Change 28.9.2 [re.submatch.op]/39 as indicated:
    template <class BiIter>
     bool operator<(const sub_match<BiIter>& lhs,
       typename iterator_traits<BiIter>::value_type const& rhs);
    

    39 Returns: lhs.str() < basic_string<typename iterator_traits<BiIter>::value_type>(1, rhs).
    39 Returns: lhs.compare(typename sub_match<BiIter>::string_type(1, rhs)) < 0.

  34. Change 28.9.2 [re.submatch.op]/40 as indicated:
    template <class BiIter>
     bool operator>(const sub_match<BiIter>& lhs,
       typename iterator_traits<BiIter>::value_type const& rhs);
    

    40 Returns: lhs.str() > basic_string<typename iterator_traits<BiIter>::value_type>(1, rhs)rhs < lhs.

  35. Change 28.9.2 [re.submatch.op]/41 as indicated:
    template <class BiIter>
     bool operator>=(const sub_match<BiIter>& lhs,
       typename iterator_traits<BiIter>::value_type const& rhs);
    

    41 Returns: lhs.str() >= basic_string<typename iterator_traits<BiIter>::value_type>(1, rhs)!(lhs < rhs).

  36. Change 28.9.2 [re.submatch.op]/42 as indicated:
    template <class BiIter>
     bool operator<=(const sub_match<BiIter>& lhs,
       typename iterator_traits<BiIter>::value_type const& rhs);
    

    42 Returns: lhs.str() <= basic_string<typename iterator_traits<BiIter>::value_type>(1, rhs)!(rhs < lhs).