Title
chrono::parse needs const charT* and basic_string_view<charT> overloads
Status
c++23
Section
[time.parse]
Submitter
Howard Hinnant

Created on 2021-05-22.00:00:00 last changed 13 months ago

Messages

Date: 2021-10-14.09:56:08

Proposed resolution:

This wording is relative to N4885.

  1. Modify [time.syn], header <chrono> synopsis, as indicated:

    […]
    namespace chrono {
      // [time.parse], parsing
      template<class charT, class Parsable>
        unspecified
          parse(const charT* fmt, Parsable& tp);
    
      template<class charT, class traits, class Alloc, class Parsable>
        unspecified
          parse(const basic_string<charT, traits, Alloc>& formatfmt, Parsable& tp);
    
      template<class charT, class traits, class Alloc, class Parsable>
        unspecified
          parse(const charT* fmt, Parsable& tp,
                basic_string<charT, traits, Alloc>& abbrev);
    
      template<class charT, class traits, class Alloc, class Parsable>
        unspecified
          parse(const basic_string<charT, traits, Alloc>& formatfmt, Parsable& tp,
                basic_string<charT, traits, Alloc>& abbrev);
    
      template<class charT, class Parsable>
        unspecified
          parse(const charT* fmt, Parsable& tp, minutes& offset);
    
      template<class charT, class traits, class Alloc, class Parsable>
        unspecified
          parse(const basic_string<charT, traits, Alloc>& formatfmt, Parsable& tp,
                minutes& offset);
    
      template<class charT, class traits, class Alloc, class Parsable>
        unspecified
          parse(const charT* fmt, Parsable& tp,
                basic_string<charT, traits, Alloc>& abbrev, minutes& offset);
    
      template<class charT, class traits, class Alloc, class Parsable>
        unspecified
          parse(const basic_string<charT, traits, Alloc>& formatfmt, Parsable& tp,
                basic_string<charT, traits, Alloc>& abbrev, minutes& offset);
    
      […]
    }
    […]
    
  2. Modify [time.parse] as indicated:

    -1- Each parse overload specified in this subclause calls from_­stream unqualified, so as to enable argument dependent lookup ([basic.lookup.argdep]). In the following paragraphs, let is denote an object of type basic_­istream<charT, traits> and let I be basic_­istream<charT, traits>&, where charT and traits are template parameters in that context.

    -?- Recommended practice: Implementations should make it difficult to accidentally store or use a manipulator that may contain a dangling reference to a format string, for example by making the manipulators produced by parse immovable and preventing stream extraction into an lvalue of such a manipulator type.

    template<class charT, class Parsable>
      unspecified
        parse(const charT* fmt, Parsable& tp);
    template<class charT, class traits, class Alloc, class Parsable>
      unspecified
        parse(const basic_string<charT, traits, Alloc>& fmt, Parsable& tp);
    

    -?- Let F be fmt for the first overload and fmt.c_str() for the second overload. Let traits be char_traits<charT> for the first overload.

    -2- Constraints: The expression

    from_stream(declval<basic_istream<charT, traits>&>(), fmt.c_str()F, tp)
    

    is well-formed when treated as an unevaluated operand.

    -3- Returns: A manipulator such that the expression is >> parse(fmt, tp) has type I, has value is, and calls from_­stream(is, fmt.c_str()F, tp).

    template<class charT, class traits, class Alloc, class Parsable>
      unspecified
        parse(const charT* fmt, Parsable& tp,
              basic_string<charT, traits, Alloc>& abbrev);
    template<class charT, class traits, class Alloc, class Parsable>
      unspecified
        parse(const basic_string<charT, traits, Alloc>& fmt, Parsable& tp,
              basic_string<charT, traits, Alloc>& abbrev);
    

    -?- Let F be fmt for the first overload and fmt.c_str() for the second overload.

    -4- Constraints: The expression

    from_stream(declval<basic_istream<charT, traits>&>(), fmt.c_str()F, tp, addressof(abbrev))
    

    is well-formed when treated as an unevaluated operand.

    -5- Returns: A manipulator such that the expression is >> parse(fmt, tp, abbrev) has type I, has value is, and calls from_­stream(is, fmt.c_str()F, tp, addressof(abbrev)).

    template<class charT, class Parsable>
      unspecified
        parse(const charT* fmt, Parsable& tp, minutes& offset);
    
    template<class charT, class traits, class Alloc, class Parsable>
      unspecified
        parse(const basic_string<charT, traits, Alloc>& fmt, Parsable& tp,
              minutes& offset);
    

    -?- Let F be fmt for the first overload and fmt.c_str() for the second overload. Let traits be char_traits<charT> and Alloc be allocator<charT> for the first overload.

    -6- Constraints: The expression

    from_stream(declval<basic_istream<charT, traits>&>(),
                fmt.c_str()F, tp,
                declval<basic_string<charT, traits, Alloc>*>(),
                &offset)
    

    is well-formed when treated as an unevaluated operand.

    -7- Returns: A manipulator such that the expression is >> parse(fmt, tp, offset) has type I, has value is, and calls:

    from_stream(is,
                fmt.c_str()F, tp,
                static_cast<basic_string<charT, traits, Alloc>*>(nullptr),
                &offset)
    
    template<class charT, class traits, class Alloc, class Parsable>
      unspecified
        parse(const charT* fmt, Parsable& tp,
              basic_string<charT, traits, Alloc>& abbrev, minutes& offset);
    
    template<class charT, class traits, class Alloc, class Parsable>
      unspecified
        parse(const basic_string<charT, traits, Alloc>& fmt, Parsable& tp,
              basic_string<charT, traits, Alloc>& abbrev, minutes& offset);
    

    -?- Let F be fmt for the first overload and fmt.c_str() for the second overload.

    -8- Constraints: The expression

    from_stream(declval<basic_istream<charT, traits>&>(),
                fmt.c_str()F, tp, addressof(abbrev), &offset)
    

    is well-formed when treated as an unevaluated operand.

    -9- Returns: A manipulator such that the expression is >> parse(fmt, tp, abbrev, offset) has type I, has value is, and calls from_­stream(is, fmt.c_str()F, tp, addressof(abbrev), &offset).

Date: 2021-10-14.00:00:00

[ 2021-10-14 Approved at October 2021 virtual plenary. Status changed: Voting → WP. ]

Date: 2021-06-15.00:00:00

[ 2021-06-23; Reflector poll ]

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

Date: 2021-06-02.00:00:00

[ 2021-06-02 Tim comments and provides updated wording ]

The current specification suggests that parse takes a reference to the format string (stream extraction on the resulting manipulator is specified to call from_stream on fmt.c_str(), not some copy), so we can't call it with a temporary string.

Additionally, since the underlying API (from_stream) requires a null-terminated string, the usual practice is to avoid providing a string_view overload (see, e.g., LWG 3430). The wording below therefore only provides const charT* overloads. It does not use "Equivalent to" to avoid requiring that the basic_string overload and the const charT* overload return the same type. As the manipulator is intended to be immediately consumed, the wording also adds normative encouragement to make misuse more difficult.

Date: 2021-05-15.00:00:00

[ 2021-05-26; Reflector poll ]

Set priority to 2 after reflector poll.

Previous resolution [SUPERSEDED]:

This wording is relative to N4885.

  1. Modify [time.syn], header <chrono> synopsis, as indicated:

    […]
    namespace chrono {
      // [time.parse], parsing
      template<class charT, class Parsable>
        unspecified
          parse(const charT* fmt, Parsable& tp);
    
      template<class charT, class traits, class Parsable>
        unspecified
          parse(basic_string_view<charT, traits> fmt, Parsable& tp);
    
      template<class charT, class traits, class Alloc, class Parsable>
        unspecified
          parse(const charT* fmt, Parsable& tp,
                basic_string<charT, traits, Alloc>& abbrev);
    
      template<class charT, class traits, class Alloc, class Parsable>
        unspecified
          parse(basic_string_view<charT, traits> fmt, Parsable& tp,
                basic_string<charT, traits, Alloc>& abbrev);
    
      template<class charT, class Parsable>
        unspecified
          parse(const charT* fmt, Parsable& tp, minutes& offset);
    
      template<class charT, class traits, class Parsable>
        unspecified
          parse(basic_string_view<charT, traits> fmt, Parsable& tp, minutes& offset);
    
      template<class charT, class traits, class Alloc, class Parsable>
      unspecified
        parse(const charT* fmt, Parsable& tp,
              basic_string<charT, traits, Alloc>& abbrev, minutes& offset);
    
      template<class charT, class traits, class Alloc, class Parsable>
        unspecified
          parse(basic_string_view<charT, traits> fmt, Parsable& tp,
                basic_string<charT, traits, Alloc>& abbrev, minutes& offset);
    
      template<class charT, class traits, class Alloc, class Parsable>
        unspecified
          parse(const basic_string<charT, traits, Alloc>& format, Parsable& tp);
    
      template<class charT, class traits, class Alloc, class Parsable>
        unspecified
          parse(const basic_string<charT, traits, Alloc>& format, Parsable& tp,
                basic_string<charT, traits, Alloc>& abbrev);
    
      template<class charT, class traits, class Alloc, class Parsable>
        unspecified
          parse(const basic_string<charT, traits, Alloc>& format, Parsable& tp,
                minutes& offset);
    
      template<class charT, class traits, class Alloc, class Parsable>
        unspecified
          parse(const basic_string<charT, traits, Alloc>& format, Parsable& tp,
                basic_string<charT, traits, Alloc>& abbrev, minutes& offset);
    
      […]
    }
    […]
    
  2. Modify [time.parse] as indicated:

    template<class charT, class Parsable>
      unspecified
        parse(const charT* fmt, Parsable& tp);
    

    -?- Constraints: The expression

    from_stream(declval<basic_istream<charT>&>(), fmt, tp)
    

    is well-formed when treated as an unevaluated operand.

    -?- Effects: Equivalent to return parse(basic_string<charT>{fmt}, tp);

    template<class charT, class traits, class Parsable>
      unspecified
        parse(basic_string_view<charT, traits> fmt, Parsable& tp);
    

    -?- Constraints: The expression

    from_stream(declval<basic_istream<charT, traits>&>(), fmt.data(), tp)
    

    is well-formed when treated as an unevaluated operand.

    -?- Effects: Equivalent to return parse(basic_string<charT, traits>{fmt}, tp);

    template<class charT, class traits, class Alloc, class Parsable>
      unspecified
        parse(const charT* fmt, Parsable& tp,
              basic_string<charT, traits, Alloc>& abbrev);
    

    -?- Constraints: The expression

    from_stream(declval<basic_istream<charT, traits>&>(), fmt, tp, addressof(abbrev))
    

    is well-formed when treated as an unevaluated operand.

    -?- Effects: Equivalent to return parse(basic_string<charT, traits, Alloc>{fmt}, tp, abbrev);

    template<class charT, class traits, class Alloc, class Parsable>
      unspecified
        parse(basic_string_view<charT, traits> fmt, Parsable& tp,
              basic_string<charT, traits, Alloc>& abbrev);
    

    -?- Constraints: The expression

    from_stream(declval<basic_istream<charT, traits>&>(), fmt.data(), tp, addressof(abbrev))
    

    is well-formed when treated as an unevaluated operand.

    -?- Effects: Equivalent to return parse(basic_string<charT, traits, Alloc>{fmt}, tp, abbrev);

    template<class charT, class Parsable>
      unspecified
        parse(const charT* fmt, Parsable& tp, minutes& offset);
    

    -?- Constraints: The expression

    from_stream(declval<basic_istream<charT>&>(), fmt, tp,
                declval<basic_string<charT>*>(),
                &offset)
    

    is well-formed when treated as an unevaluated operand.

    -?- Effects: Equivalent to return parse(basic_string<charT>{fmt}, tp, offset);

    template<class charT, class traits, class Parsable>
      unspecified
        parse(basic_string_view<charT, traits> fmt, Parsable& tp, minutes& offset);
    

    -?- Constraints: The expression

    from_stream(declval<basic_istream<charT, traits>&>(), fmt.data(), tp,
                declval<basic_string<charT, traits>*>(),
                &offset)
    

    is well-formed when treated as an unevaluated operand.

    -?- Effects: Equivalent to return parse(basic_string<charT, traits>{fmt}, tp, offset);

    template<class charT, class traits, class Alloc, class Parsable>
    unspecified
      parse(const charT* fmt, Parsable& tp,
            basic_string<charT, traits, Alloc>& abbrev, minutes& offset);
    

    -?- Constraints: The expression

    from_stream(declval<basic_istream<charT, traits>&>(), fmt, tp, addressof(abbrev), &offset)
    

    is well-formed when treated as an unevaluated operand.

    -?- Effects: Equivalent to return parse(basic_string<charT, traits, Alloc>{fmt}, tp, abbrev, offset);

    template<class charT, class traits, class Alloc, class Parsable>
      unspecified
        parse(basic_string_view<charT, traits> fmt, Parsable& tp,
              basic_string<charT, traits, Alloc>& abbrev, minutes& offset);
    

    -?- Constraints: The expression

    from_stream(declval<basic_istream<charT, traits>&>(), fmt.data(), tp, addressof(abbrev), &offset)
    

    is well-formed when treated as an unevaluated operand.

    -?- Effects: Equivalent to return parse(basic_string<charT, traits, Alloc>{fmt}, tp, abbrev, offset);

    template<class charT, class traits, class Alloc, class Parsable>
      unspecified
        parse(const basic_string<charT, traits, Alloc>& format, Parsable& tp);
    

    -2- Constraints: The expression

    from_stream(declval<basic_istream<charT, traits>&>(), fmt.c_str(), tp)
    

    is well-formed when treated as an unevaluated operand.

    -3- Returns: A manipulator such that the expression is >> parse(fmt, tp) has type I, has value is, and calls from_stream(is, fmt.c_str(), tp).

Date: 2021-05-22.00:00:00

The chrono::parse functions take const basic_string<charT, traits, Alloc>& parameters to specify the format strings for the parse. Due to an oversight on my part in the proposal, overloads taking const charT* and basic_string_view<charT, traits> were omitted. These are necessary when the supplied arguments is a string literal or string_view respectively:

in >> parse("%F %T", tp);

These overloads have been implemented in the example implementation.

History
Date User Action Args
2023-11-22 15:47:43adminsetstatus: wp -> c++23
2021-10-14 09:56:08adminsetmessages: + msg12123
2021-10-14 09:56:08adminsetstatus: voting -> wp
2021-09-29 12:57:28adminsetstatus: ready -> voting
2021-06-23 14:16:45adminsetmessages: + msg11960
2021-06-23 14:16:45adminsetstatus: new -> ready
2021-06-02 05:33:21adminsetmessages: + msg11864
2021-05-26 10:52:50adminsetmessages: + msg11853
2021-05-22 22:17:34adminsetmessages: + msg11845
2021-05-22 00:00:00admincreate