727. regex_replace() doesn't accept basic_strings with custom traits and allocators

Section: 31.11.4 [re.alg.replace] Status: C++11 Submitter: Stephan T. Lavavej Opened: 2007-09-22 Last modified: 2016-02-10

Priority: Not Prioritized

View all other issues in [re.alg.replace].

View all issues with C++11 status.

Discussion:

regex_match() and regex_search() take const basic_string<charT, ST, SA>&. regex_replace() takes const basic_string<charT>&. This prevents regex_replace() from accepting basic_strings with custom traits and allocators.

Overloads of regex_replace() taking basic_string should be additionally templated on class ST, class SA and take const basic_string<charT, ST, SA>&. Consistency with regex_match() and regex_search() would place class ST, class SA as the first template arguments; compatibility with existing code using TR1 and giving explicit template arguments to regex_replace() would place class ST, class SA as the last template arguments.

[ Batavia (2009-05): ]

Bill comments, "We need to look at the depth of this change."

Pete remarks that we are here dealing with a convenience function that saves a user from calling the iterato-based overload.

Move to Open.

[ 2009-07 Frankfurt: ]

Howard to ask Stephan Lavavej to provide wording.

[ 2009-07-17 Stephan provided wording. ]

[ 2009-07-25 Daniel tweaks both this issue and 726. ]

One relevant part of the proposed resolution below suggests to add a new overload of the format member function in the match_results class template that accepts two character pointers defining the begin and end of a format range. A more general approach could have proposed a pair of iterators instead, but the used pair of char pointers reflects existing practice. If the committee strongly favors an iterator-based signature, this could be simply changed. I think that the minimum requirement should be a BidirectionalIterator, but current implementations take advantage (at least partially) of the RandomAccessIterator sub interface of the char pointers.

Suggested Resolution:

[Moved into the proposed resloution]

[ 2009-07-30 Stephan agrees with Daniel's wording. Howard places Daniel's wording in the Proposed Resolution. ]

[ 2009-10 Santa Cruz: ]

Move to Review. Chair is anxious to move this to Ready in Pittsburgh.

[ 2010-01-27 Moved to Tentatively Ready after 5 positive votes on c++std-lib. ]

Proposed resolution:

  1. Change 31.4 [re.syn] as indicated:

    // 28.11.4, function template regex_replace:
    template <class OutputIterator, class BidirectionalIterator,
              class traits, class charT, class ST, class SA>
      OutputIterator
      regex_replace(OutputIterator out,
                    BidirectionalIterator first, BidirectionalIterator last,
                    const basic_regex<charT, traits>& e,
                    const basic_string<charT, ST, SA>& fmt,
                    regex_constants::match_flag_type flags =
                      regex_constants::match_default);
    
    
    template <class OutputIterator, class BidirectionalIterator,
              class traits, class charT>
      OutputIterator
      regex_replace(OutputIterator out,
                    BidirectionalIterator first, BidirectionalIterator last,
                    const basic_regex<charT, traits>& e,
                    const charT* fmt,
                    regex_constants::match_flag_type flags =
                      regex_constants::match_default);
    
    
    template <class traits, class charT, class ST, class SA,
              class FST, class FSA>
      basic_string<charT, ST, SA>
      regex_replace(const basic_string<charT, ST, SA>& s,
                    const basic_regex<charT, traits>& e,
                    const basic_string<charT, FST, FSA>& fmt,
                    regex_constants::match_flag_type flags =
                      regex_constants::match_default);
    
    
    template <class traits, class charT, class ST, class SA>
      basic_string<charT, ST, SA>
      regex_replace(const basic_string<charT, ST, SA>& s,
                    const basic_regex<charT, traits>& e,
                    const charT* fmt,
                    regex_constants::match_flag_type flags =
                      regex_constants::match_default);
    
    
    
    template <class traits, class charT, class ST, class SA>
      basic_string<charT>
      regex_replace(const charT* s,
                    const basic_regex<charT, traits>& e,
                    const basic_string<charT, ST, SA>& fmt,
                    regex_constants::match_flag_type flags =
                      regex_constants::match_default);
    
    
    
    template <class traits, class charT>
      basic_string<charT>
      regex_replace(const charT* s,
                    const basic_regex<charT, traits>& e,
                    const charT* fmt,
                    regex_constants::match_flag_type flags =
                      regex_constants::match_default);
    
    
  2. Change 31.10 [re.results]/3, class template match_results as indicated:

    
    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 string_typebasic_string<char_type, ST, SA>& fmt,
             regex_constants::match_flag_type flags =
               regex_constants::format_default) const;
    
    template <class ST, class SA>
      string_typebasic_string<char_type, ST, SA>
      format(const string_typebasic_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;
    
    
  3. Insert at the very beginning of 31.10.5 [re.results.form] the following:

    
    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;
    
    

    1 Requires: The type OutputIter shall satisfy the requirements for an Output Iterator (27.2.4 [output.iterators]).

    2 Effects: Copies the character sequence [fmt_first,fmt_last) to OutputIter out. Replaces each format specifier or escape sequence in the copied range with either the character(s) it represents or the sequence of characters within *this to which it refers. The bitmasks specified in flags determine which format specifiers and escape sequences are recognized.

    3 Returns: out.

  4. Change 31.10.5 [re.results.form], before p. 1 until p. 3 as indicated:

    template <class OutputIter, class ST, class SA>
      OutputIter
      format(OutputIter out,
             const string_typebasic_string<char_type, ST, SA>& fmt,
             regex_constants::match_flag_type flags =
               regex_constants::format_default) const;
    

    1 Requires: The type OutputIter shall satisfy the requirements for an Output Iterator (24.2.3).

    2 Effects: Copies the character sequence [fmt.begin(),fmt.end()) to OutputIter out. Replaces each format specifier or escape sequence in fmt with either the character(s) it represents or the sequence of characters within *this to which it refers. The bitmasks specified in flags determines what format specifiers and escape sequences are recognized Equivalent to return format(out, fmt.data(), fmt.data() + fmt.size(), flags).

    3 Returns: out.

  5. Change 31.10.5 [re.results.form], before p. 4 until p. 4 as indicated:

    template <class ST, class SA>
      string_typebasic_string<char_type, ST, SA>
      format(const string_typebasic_string<char_type, ST, SA>& fmt,
             regex_constants::match_flag_type flags =
               regex_constants::format_default) const;
    

    Effects: Returns a copy of the string fmt. Replaces each format specifier or escape sequence in fmt with either the character(s) it represents or the sequence of characters within *this to which it refers. The bitmasks specified in flags determines what format specifiers and escape sequences are recognized. Constructs an empty string result of type basic_string<char_type, ST, SA>, and calls format(back_inserter(result), fmt, flags).

    Returns: result

  6. At the end of 31.10.5 [re.results.form] insert as indicated:

    
    string_type
      format(const char_type* fmt,
             regex_constants::match_flag_type flags =
               regex_constants::format_default) const;
    

    Effects: Constructs an empty string result of type string_type, and calls format(back_inserter(result), fmt, fmt + char_traits<char_type>::length(fmt), flags).

    Returns: result

  7. Change 31.11.4 [re.alg.replace] before p. 1 as indicated:

    template <class OutputIterator, class BidirectionalIterator,
              class traits, class charT, class ST, class SA>
      OutputIterator
      regex_replace(OutputIterator out,
                    BidirectionalIterator first, BidirectionalIterator last,
                    const basic_regex<charT, traits>& e,
                    const basic_string<charT, ST, SA>& fmt,
                    regex_constants::match_flag_type flags =
                      regex_constants::match_default);
    
    
    template <class OutputIterator, class BidirectionalIterator,
              class traits, class charT>
      OutputIterator
      regex_replace(OutputIterator out,
                    BidirectionalIterator first, BidirectionalIterator last,
                    const basic_regex<charT, traits>& e,
                    const charT* fmt,
                    regex_constants::match_flag_type flags =
                      regex_constants::match_default);
    

    Effects: [..]. If any matches are found then, for each such match, if !(flags & regex_constants::format_no_copy) calls std::copy(m.prefix().first, m.prefix().second, out), and then calls m.format(out, fmt, flags) for the first form of the function and m.format(out, fmt, fmt + char_traits<charT>::length(fmt), flags) for the second form. [..].

  8. Change 31.11.4 [re.alg.replace] before p. 3 as indicated:

    template <class traits, class charT, class ST, class SA,
              class FST, class FSA>
      basic_string<charT, ST, SA>
      regex_replace(const basic_string<charT, ST, SA>& s,
                    const basic_regex<charT, traits>& e,
                    const basic_string<charT, FST, FSA>& fmt,
                    regex_constants::match_flag_type flags =
                      regex_constants::match_default);
    
    
    template <class traits, class charT, class ST, class SA>
      basic_string<charT, ST, SA>
      regex_replace(const basic_string<charT, ST, SA>& s,
                    const basic_regex<charT, traits>& e,
                    const charT* fmt,
                    regex_constants::match_flag_type flags =
                      regex_constants::match_default);
    

    Effects: Constructs an empty string result of type basic_string<charT, ST, SA>, calls regex_replace(back_inserter(result), s.begin(), s.end(), e, fmt, flags), and then returns result.

  9. At the end of 31.11.4 [re.alg.replace] add the following new prototype description:

    
    template <class traits, class charT, class ST, class SA>
      basic_string<charT>
      regex_replace(const charT* s,
                    const basic_regex<charT, traits>& e,
                    const basic_string<charT, ST, SA>& fmt,
                    regex_constants::match_flag_type flags =
                      regex_constants::match_default);
    
    
    
    template <class traits, class charT>
      basic_string<charT>
      regex_replace(const charT* s,
                    const basic_regex<charT, traits>& e,
                    const charT* fmt,
                    regex_constants::match_flag_type flags =
                      regex_constants::match_default);
    

    Effects: Constructs an empty string result of type basic_string<charT>, calls regex_replace(back_inserter(result), s, s + char_traits<charT>::length(s), e, fmt, flags), and then returns result.