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

### 3540. §[format.arg] There should be no `const` in `basic_format_arg(const T* p)`

Section: 20.20.7.1 [format.arg] Status: WP Submitter: S. B. Tam Opened: 2021-04-07 Last modified: 2021-06-07

Priority: Not Prioritized

View all other issues in [format.arg].

View all issues with WP status.

Discussion:

When P0645R10 "Text formatting" was merged into the draft standard, there was a typo: an exposition-only constructor of `basic_format_arg` is declared as accepting `const T*` in the class synopsis, but is later declared to accept `T*`. This was editorial issue 3461 and was resolved by adding `const` to the redeclaration.

As it is, constructing `basic_format_arg` from `void*` will select `template<class T> explicit basic_format_arg(const T& v)` and store a `basic_format_arg::handle` instead of select `template<class T> basic_format_arg(const T*)` and store a `const void*`, because `void*` → `void*const&` is identity conversion, while `void*` → `const void*` is qualification conversion.

While this technically works, it seems that storing a `const void*` would be more intuitive.

Hence, I think `const` should be removed from both declarations of `basic_format_arg(const T*)`, so that construction from `void*` will select this constructor, resulting in more intuitive behavior.

[2021-04-20; Reflector poll]

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

[2021-06-07 Approved at June 2021 virtual plenary. Status changed: Voting → WP.]

Proposed resolution:

This wording is relative to N4885.

1. Modify 20.20.7.1 [format.arg] as indicated:

   > >     namespace std {
   > >       template<class Context>
   > >       class basic_format_arg {
   > >       public:
   > >         class handle;

   > >       private:
   > >         using char_type = typename Context::char_type;                     // exposition only

   > >         variant<monostate, bool, char_type,
   > >           int, unsigned int, long long int, unsigned long long int,
   > >           float, double, long double,
   > >           const char_type*, basic_string_view<char_type>,
   > >           const void*, handle> value;                                      // exposition only

   > >         template<class T> explicit basic_format_arg(const T& v) noexcept;  // exposition only
   > >         explicit basic_format_arg(float n) noexcept;                       // exposition only
   > >         explicit basic_format_arg(double n) noexcept;                      // exposition only
   > >         explicit basic_format_arg(long double n) noexcept;                 // exposition only
   > >         explicit basic_format_arg(const char_type* s);                     // exposition only

   > >         template<class traits>
   > >           explicit basic_format_arg(
   > >             basic_string_view<char_type, traits> s) noexcept;              // exposition only

   > >         template<class traits, class Allocator>
   > >           explicit basic_format_arg(
   > >             const basic_string<char_type, traits, Allocator>& s) noexcept; // exposition only

   > >         explicit basic_format_arg(nullptr_t) noexcept;                     // exposition only

   > >         template<class T>
   > >           explicit basic_format_arg(const T* p) noexcept;                  // exposition only
   > >       public:
   > >         basic_format_arg() noexcept;

   > >         explicit operator bool() const noexcept;
   > >       };
   > >     }

   > […]

   >     template<class T> explicit basic_format_arg(const T* p) noexcept;

   > > -12- Constraints: `is_void_v<T>` is `true`.

   > > -13- Effects: Initializes `value` with `p`.

   > > -14- [Note 1: Constructing `basic_format_arg` from a pointer to a member is ill-formed unless the user provides an enabled specialization of formatter for that pointer to member type. — end note]