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

3806. Should concept formattable<T, charT> default to char?

Section: 28.5.6.3 [format.formattable] Status: NAD Submitter: Jonathan Wakely Opened: 2022-10-28 Last modified: 2023-01-24

Priority: 2

View all other issues in [format.formattable].

View all issues with NAD status.

Discussion:

For many uses of <format> there's no need to explicitly mention the output type as char. There are either typedefs for char specializations (format_context, format_parse_context, format_args, etc.) or a default template argument (formatter, range_formatter). But for the new formattable concept you always need to specify the character type:

static_assert( std::formattable<int> ); // ill-formed
static_assert( std::formattable<int, char> ); // OK

Should the concept have a default template argument for the second parameter, to make it easier to check whether something is formattable as char?

[2022-11-01; Reflector poll]

Set priority to 2 after reflector poll. Two votes for NAD, the convenience makes it easier to misuse.

[2022-11-30; Reflector poll]

Set status to "Tentatively NAD" after ten votes in reflector poll.

[2022-11-30 LWG telecon. Status changed: Tentatively NAD → NAD.]

[2023-01-24 LEWG electronic poll; weak consensus to reject the propsed change.]

Proposed resolution:

This wording is relative to N4917.

  1. Modify 28.5.1 [format.syn] as indicated:

    […]
    // 28.5.6 [format.formatter], formatter
    template<class T, class charT = char> struct formatter;
    
    // 28.5.6.3 [format.formattable], concept formattable
    template<class T, class charT = char>
      concept formattable = see below;
    […]
    
  2. Modify 28.5.6.3 [format.formattable] as indicated:

    [Drafting note: This repeats the default template argument already shown in the synopsis, which would not be valid in C++ code. That is consistent with our presentation style though, as this is not C++ code, it's a specification. See e.g. indirect_strict_weak_order and subrange.]

    -1- Let fmt-iter-for<charT> be an unspecified type that models output_iterator<const charT&> (24.3.4.10 [iterator.concept.output]).

    template<class T, class charT = char>
      concept formattable =
        semiregular<formatter<remove_cvref_t<T>, charT>> &&
        requires(formatter<remove_cvref_t<T>, charT> f,
                 const formatter<remove_cvref_t<T>, charT> cf,
                 T t,
                 basic_format_context<fmt-iter-for<charT>, charT> fc,
                 basic_format_parse_context<charT> pc) {
          { f.parse(pc) } -> same_as<basic_format_parse_context<charT>::iterator>;
          { cf.format(t, fc) } -> same_as<fmt-iter-for<charT>>;
        };