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

3631. basic_format_arg(T&&) should use remove_cvref_t<T> throughout

Section: 22.14.7.1 [format.arg] Status: New Submitter: Tim Song Opened: 2021-11-03 Last modified: 2022-01-30

Priority: 3

View other active issues in [format.arg].

View all other issues in [format.arg].

View all issues with New status.

Discussion:

P2418R2 changed basic_format_arg's constructor to take a forwarding reference but didn't change 22.14.7.1 [format.arg]/5 which inspects various properties of T. Now that the deduced type can be cvref-qualified, they need to be removed before the checks.

[2022-01-29; Reflector poll]

Set priority to 3 after reflector poll.

Proposed resolution:

This wording is relative to N4901.

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

    template<class T> explicit basic_format_arg(T&& v) noexcept;
    

    -?- Let TD be remove_cvref_t<T>.

    -4- Constraints: The template specialization

    typename Context::template formatter_type<remove_cvref_t<T>TD>
    

    meets the BasicFormatter requirements (22.14.6.1 [formatter.requirements]). The extent to which an implementation determines that the specialization meets the BasicFormatter requirements is unspecified, except that as a minimum the expression

    typename Context::template formatter_type<remove_cvref_t<T>TD>()
      .format(declval<T&>(), declval<Context&>())
    

    shall be well-formed when treated as an unevaluated operand (7.2.3 [expr.context]).

    -5- Effects:

    1. (5.1) — if TD is bool or char_type, initializes value with v;

    2. (5.2) — otherwise, if TD is char and char_type is wchar_t, initializes value with static_cast<wchar_t>(v);

    3. (5.3) — otherwise, if TD is a signed integer type (6.8.2 [basic.fundamental]) and sizeof(TD) <= sizeof(int), initializes value with static_cast<int>(v);

    4. (5.4) — otherwise, if TD is an unsigned integer type and sizeof(TD) <= sizeof(unsigned int), initializes value with static_cast<unsigned int>(v);

    5. (5.5) — otherwise, if TD is a signed integer type and sizeof(TD) <= sizeof(long long int), initializes value with static_cast<long long int>(v);

    6. (5.6) — otherwise, if TD is an unsigned integer type and sizeof(TD) <= sizeof(unsigned long long int), initializes value with static_cast<unsigned long long int>(v);

    7. (5.7) — otherwise, initializes value with handle(v).