Title
Avoid parsing format-spec if it is not present or empty
Status
nad
Section
[formatter.requirements]
Submitter
Mark de Wever

Created on 2022-08-28.00:00:00 last changed 17 months ago

Messages

Date: 2023-06-16.09:31:14

Proposed resolution:

This wording is relative to N4917.

  1. Modify [formatter.requirements] as indicated:

    -3- Given character type charT, output iterator type Out, and formatting argument type T, in Table 74 and Table 75:

    […]

    pc.begin() points to the beginning of the format-spec ([format.string]) of the replacement field being formatted in the format string. If format-spec is not present or empty then either pc.begin() == pc.end() or *pc.begin() == '}'.

  2. Modify BasicFormatter requirements [tab:formatter.basic] as indicated:

    Table 74: BasicFormatter requirements [tab:formatter.basic]
    Expression Return type Requirement
    f.format(u, fc) FC::iterator Formats u according to the specifiers stored in
    *this, writes the output to fc.out(), and returns
    an iterator past the end of the output range.
    The output shall only depend on u, fc.locale(),
    fc.arg(n) for any value n of type size_t, and
    the range [pc.begin(), pc.end()) from the last
    call to f.parse(pc). When the format-spec
    ([format.string]) is not present or empty
    the call to f.parse(pc) is omitted.
  3. Modify Formatter requirements [tab:formatter] as indicated:

    Table 75: Formatter requirements [tab:formatter]
    Expression Return type Requirement
    f.format(t, fc) FC::iterator Formats t according to the specifiers stored in
    *this, writes the output to fc.out(), and returns
    an iterator past the end of the output range.
    The output shall only depend on t, fc.locale(),
    fc.arg(n) for any value n of type size_t, and
    the range [pc.begin(), pc.end()) from the last
    call to f.parse(pc). When the format-spec
    ([format.string]) is not present or empty
    the call to f.parse(pc) is omitted.
  4. Modify [format.arg] as indicated:

    […]

    -16- The class handle allows formatting an object of a user-defined type.

    namespace std {
      template<class Context>
      class basic_format_arg<Context>::handle {
        const void* ptr_;                                          // exposition only
        void (*format_)(basic_format_parse_context<char_type>&*,
                        Context&, const void*);                    // exposition only
    
        template<class T> explicit handle(T&& val) noexcept;       // exposition only
    
        friend class basic_format_arg<Context>;                    // exposition only
    
      public:
        void format(basic_format_parse_context<char_type>&, Context& ctx) const;
      };
    }
    
    template<class T> explicit handle(T&& val) noexcept;
    

    -17- […]

    -18- […]

    -19- Effects: Initializes ptr_ with addressof(val) and format_ with

    [](basic_format_parse_context<char_type>&* parse_ctx,
       Context& format_ctx, const void* ptr) {
      typename Context::template formatter_type<TD> f;
      if (parse_ctx) parse_ctx.->advance_to(f.parse(*parse_ctx));
      format_ctx.advance_to(f.format(*const_cast<TQ*>(static_cast<const TD*>(ptr)),
                                     format_ctx));
    }
    
    void format(basic_format_parse_context<char_type>& parse_ctx, Context& format_ctx) const;
    

    -20- Effects: If the format-spec ([format.string]) is not present or empty, equivalent to:

    format_(nullptr, format_ctx, ptr_);
    

    otherwise, eEquivalent to:

    format_(addressof(parse_ctx), format_ctx, ptr_);
    
Date: 2023-06-16.09:31:14

[ Varna 2023-06-16; Status changed: LEWG → NAD. ]

Resolved differently by LWG 3892.

Date: 2023-02-07.22:36:40

[ Issaquah 2023-02-07; LWG ]

Will be resolved differently by P2733.

Date: 2022-10-15.00:00:00

[ 2022-10-12; Reflector poll ]

Set status to "LEWG" and priority to 3 after reflector poll.

Several votes for NAD as this would be a design change requiring a paper. Dissenting opinions: "Different handling of empty and default specs is entirely incidental and not a design feature. Moreover, built-in formatters treat these cases identically so it's a good idea to make this explicit." "Don't need a full paper to clarify the meaning of "don't call member parse if there's no format spec". If LEWG agree the direction PR can be polished."

Date: 2022-08-28.00:00:00

A format string [format.string.general]/1 has an optional format-specifier replacement field. If this field is not present, the current wording makes it clear the intention is to call parse when a formatting argument use a handle class [format.arg]/19

Effects: Initializes ptr_ with addressof(val) and format_ with

   [](basic_format_parse_context<char_type>& parse_ctx,
      Context& format_ctx, const void* ptr) {
     typename Context::template formatter_type<TD> f;
     parse_ctx.advance_to(f.parse(parse_ctx));
     format_ctx.advance_to(f.format(*const_cast<TQ*>(static_cast<const TD*>(ptr)),
                                    format_ctx));
  }

For other types it is implied by [tab:formatter.basic]

Formats u according to the specifiers stored in *this, writes the output to fc.out(), and returns an iterator past the end of the output range. The output shall only depend on u, fc.locale(), fc.arg(n) for any value n of type size_t, and the range [pc.begin(), pc.end()) from the last call to f.parse(pc).

(Similar wording is used in [tab:formatter])

Before the parse function is called it is known whether or not a format-spec is present. It seems wasteful to call a function that is known not to parse anything. Therefore I propose to make the call optional.

This change is only observable for formatter specializations using the handle class, for the formatter specializations in [format.formatter.spec] the change has no observable effect.

History
Date User Action Args
2023-06-16 09:31:14adminsetmessages: + msg13640
2023-06-16 09:31:14adminsetstatus: lewg -> nad
2023-02-07 22:36:40adminsetmessages: + msg13290
2022-10-12 14:38:10adminsetmessages: + msg12857
2022-10-12 14:38:10adminsetstatus: new -> lewg
2022-09-17 11:09:13adminsetmessages: + msg12765
2022-08-28 00:00:00admincreate