3833. Remove specialization template<size_t N> struct formatter<const charT[N], charT>

Section: 28.5.6.4 [format.formatter.spec] Status: C++23 Submitter: Mark de Wever Opened: 2022-11-27 Last modified: 2023-11-22

Priority: 2

View other active issues in [format.formatter.spec].

View all other issues in [format.formatter.spec].

View all issues with C++23 status.

Discussion:

In the past I discussed with Victor and Charlie to remove

template<size_t N> struct formatter<const charT[N], charT>;

Charlie disliked that since MSVC STL already shipped it and Victor mentioned it was useful. Instead of proposing to remove the specialization in LWG 3701 ("Make formatter<remove_cvref_t<const charT[N]>, charT> requirement explicit") I proposed to keep it. It's unused but it doesn't hurt.

That was until P2585R0 "Improve default container formatting". This paper makes it no longer possible to instantiate this specialization. See here for an example and a possible work-around.

The relevant wording is 28.5.1 [format.syn]:

template<class R>
  constexpr unspecified format_kind = unspecified;

template<ranges::input_range R>
    requires same_as<R, remove_cvref_t<R>>
  constexpr range_format format_kind<R> = see below;

combined with 28.5.7.1 [format.range.fmtkind] p1:

A program that instantiates the primary template of format_kind is ill-formed.

The issue is that const charT[N] does not satisfy the requirement same_as<R, remove_cvref_t<R>>. So it tries to instantiate the primary template, which is ill-formed.

I see two possible solutions:

  1. Removing the specialization

    template<size_t N> struct formatter<const charT[N], charT>;
    
  2. Adding a specialization

    template<class charT, size_t N>
      constexpr range_format format_kind<const charT[N]> =
        range_format::disabled;
    

I discussed this issue privately and got no objection for solution 1, therefore I propose to take that route. Implementations can still implement solution 2 as an extension until they are ready to ship an API/ABI break.

[2022-11-30; Reflector poll]

Set priority to 2 after reflector poll.

"Rationale is not really convincing why the first option is the right one."

"The point is not that we would need to add a format_kind specialization, it is that the specialization is inconsistent with the design of formatter, which is supposed to be instantiated only for cv-unqualified non-reference types."

Previous resolution [SUPERSEDED]:

This wording is relative to N4917.

  1. Modify 28.5.6.4 [format.formatter.spec] as indicated:

    -2- Let charT be either char or wchar_t. Each specialization of formatter is either enabled or disabled, as described below. A debug-enabled specialization of formatter additionally provides a public, constexpr, non-static member function set_debug_format() which modifies the state of the formatter to be as if the type of the std-format-spec parsed by the last call to parse were ?. Each header that declares the template formatter provides the following enabled specializations:

    1. (2.1) — The debug-enabled specializations […]

    2. (2.2) — For each charT, the debug-enabled string type specializations

      template<> struct formatter<charT*, charT>;
      template<> struct formatter<const charT*, charT>;
      template<size_t N> struct formatter<charT[N], charT>;
      template<size_t N> struct formatter<const charT[N], charT>;
      template<class traits, class Allocator>
        struct formatter<basic_string<charT, traits, Allocator>, charT>;
      template<class traits>
        struct formatter<basic_string_view<charT, traits>, charT>;
      
    3. (2.3) — […]

    4. (2.4) — […]

  2. Add a new paragraph to C.2.10 [diff.cpp20.utilities] as indicated:

    Affected subclause: 28.5.6.4 [format.formatter.spec]

    Change: Remove the formatter specialization template<size_t N> struct formatter<const charT[N], charT>.

    Rationale: The formatter specialization was not used in the Standard library. Keeping the specialization well-formed required an additional format_kind specialization.

    Effect on original feature: Valid C++ 2020 code that instantiated the removed specialization is now ill-formed.

[2023-02-07 Tim provides updated wording]

[Issaquah 2023-02-08; LWG]

Unanimous consent to move to Immediate.

[2023-02-13 Approved at February 2023 meeting in Issaquah. Status changed: Immediate → WP.]

Proposed resolution:

This wording is relative to N4928.

  1. Modify 28.5.6.4 [format.formatter.spec] as indicated:

    -2- Let charT be either char or wchar_t. Each specialization of formatter is either enabled or disabled, as described below. A debug-enabled specialization of formatter additionally provides a public, constexpr, non-static member function set_debug_format() which modifies the state of the formatter to be as if the type of the std-format-spec parsed by the last call to parse were ?. Each header that declares the template formatter provides the following enabled specializations:

    1. (2.1) — The debug-enabled specializations […]

    2. (2.2) — For each charT, the debug-enabled string type specializations

      template<> struct formatter<charT*, charT>;
      template<> struct formatter<const charT*, charT>;
      template<size_t N> struct formatter<charT[N], charT>;
      template<size_t N> struct formatter<const charT[N], charT>;
      template<class traits, class Allocator>
        struct formatter<basic_string<charT, traits, Allocator>, charT>;
      template<class traits>
        struct formatter<basic_string_view<charT, traits>, charT>;
      
    3. (2.3) — […]

    4. (2.4) — […]

  2. Add a new paragraph to C.2.10 [diff.cpp20.utilities] as indicated:

    Affected subclause: 28.5.6.4 [format.formatter.spec]

    Change: Removed the formatter specialization template<size_t N> struct formatter<const charT[N], charT>.

    Rationale: The specialization is inconsistent with the design of formatter, which is intended to be instantiated only with cv-unqualified object types.

    Effect on original feature: Valid C++ 2020 code that instantiated the removed specialization can become ill-formed.