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.

### 3539. `format_to` must not copy models of `output_iterator<const charT&>`

Section: 20.20.5 [format.functions] Status: WP Submitter: Casey Carter Opened: 2021-03-31 Last modified: 2021-06-07

Priority: Not Prioritized

View all other issues in [format.functions].

View all issues with WP status.

Discussion:

20.20.5 [format.functions] specifies the overloads of `format_to` as:

>     template<class Out, class... Args>
>       Out format_to(Out out, string_view fmt, const Args&... args);
>     template<class Out, class... Args>
>       Out format_to(Out out, wstring_view fmt, const Args&... args);

> > -8- Effects: Equivalent to:

> > >     using context = basic_format_context<Out, decltype(fmt)::value_type>;
> > >     return vformat_to(out, fmt, make_format_args<context>(args...));

>     template<class Out, class... Args>
>       Out format_to(Out out, const locale& loc, string_view fmt, const Args&... args);
>     template<class Out, class... Args>
>       Out format_to(Out out, const locale& loc, wstring_view fmt, const Args&... args);
>       Out format_to(Out out, wstring_view fmt, const Args&... args);

> > -9- Effects: Equivalent to:

> > >     using context = basic_format_context<Out, decltype(fmt)::value_type>;
> > >     return vformat_to(out, loc, fmt, make_format_args<context>(args...));

but the overloads of `vformat_to` take their first argument by value (from the same subclause):

>     template<class Out>
>       Out vformat_to(Out out, string_view fmt,
>                      format_args_t<type_identity_t<Out>, char> args);
>     template<class Out>
>       Out vformat_to(Out out, wstring_view fmt,
>                      format_args_t<type_identity_t<Out>, wchar_t> args);
>     template<class Out>
>       Out vformat_to(Out out, const locale& loc, string_view fmt,
>                      format_args_t<type_identity_t<Out>, char> args);
>     template<class Out>
>       Out vformat_to(Out out, const locale& loc, wstring_view fmt,
>                      format_args_t<type_identity_t<Out>, wchar_t> args);

> > -10- Let `charT` be `decltype(fmt)::value_type`.

> > -11- Constraints: `Out` satisfies `output_iterator<const charT&>`.

> > -12- Preconditions: `Out` models `output_iterator<const charT&>`.

and require its type to model `output_iterator<const charT&>`. `output_iterator<T, U>` refines `input_or_output_iterator<T>` which refines `movable<T>`, but it notably does not refine `copyable<T>`. Consequently, the "Equivalent to" code for the `format_to` overloads is copying an iterator that could be move-only. I suspect it is not the intent that calls to `format_to` with move-only iterators be ill-formed, but that it was simply an oversight that this wording needs updating to be consistent with the change to allow move-only single-pass iterators in C++20.

[2021-04-20; Reflector poll]

Set status to Tentatively Ready after seven 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.5 [format.functions] as indicated:

   >     template<class Out, class... Args>
   >       Out format_to(Out out, string_view fmt, const Args&... args);
   >     template<class Out, class... Args>
   >       Out format_to(Out out, wstring_view fmt, const Args&... args);

   > > -8- Effects: Equivalent to:

   > > >     using context = basic_format_context<Out, decltype(fmt)::value_type>;
   > > >     return vformat_to(std::move(out), fmt, make_format_args<context>(args...));

   >     template<class Out, class... Args>
   >       Out format_to(Out out, const locale& loc, string_view fmt, const Args&... args);
   >     template<class Out, class... Args>
   >       Out format_to(Out out, const locale& loc, wstring_view fmt, const Args&... args);

   > > -9- Effects: Equivalent to:

   > > >     using context = basic_format_context<Out, decltype(fmt)::value_type>;
   > > >     return vformat_to(std::move(out), loc, fmt, make_format_args<context>(args...));