From 45b673f2265b79f4b07584d2d39df8d2e1a63c3b Mon Sep 17 00:00:00 2001 From: Jens Maurer Date: Thu, 7 Oct 2021 22:16:34 +0200 Subject: [PATCH 1/2] P2418R2 Add support for std::generator-like types to std::format --- source/compatibility.tex | 18 +++++ source/utilities.tex | 164 ++++++++++++++++++++++++--------------- 2 files changed, 120 insertions(+), 62 deletions(-) diff --git a/source/compatibility.tex b/source/compatibility.tex index d4472f8f5d..76b01589e8 100644 --- a/source/compatibility.tex +++ b/source/compatibility.tex @@ -76,6 +76,24 @@ // previously threw \tcode{format_error} \end{codeblock} +\diffref{format} +\change +Signature changes: \tcode{format}, \tcode{format_to}, \tcode{format_to_n}, +\tcode{formatted_size}. +\rationale +Enable formatting of views that are neither const-iterable nor copyable. +\effect +Valid \CppXX{} code that passes bit fields to formatting functions +may become ill-formed. For example: +\begin{codeblock} +struct tiny { + int bit: 1; +}; + +auto t = tiny(); +std::format("{}", t.bit); // ill-formed, previously returned \tcode{"0"} +\end{codeblock} + \rSec1[diff.cpp17]{\Cpp{} and ISO \CppXVII{}} \rSec2[diff.cpp17.general]{General} diff --git a/source/utilities.tex b/source/utilities.tex index 17ed34b9e7..683e0cc705 100644 --- a/source/utilities.tex +++ b/source/utilities.tex @@ -19672,13 +19672,13 @@ // \ref{format.functions}, formatting functions template - string format(@\exposid{format-string}@ fmt, const Args&... args); + string format(@\exposid{format-string}@ fmt, Args&&... args); template - wstring format(@\exposid{wformat-string}@ fmt, const Args&... args); + wstring format(@\exposid{wformat-string}@ fmt, Args&&... args); template - string format(const locale& loc, @\exposid{format-string}@ fmt, const Args&... args); + string format(const locale& loc, @\exposid{format-string}@ fmt, Args&&... args); template - wstring format(const locale& loc, @\exposid{wformat-string}@ fmt, const Args&... args); + wstring format(const locale& loc, @\exposid{wformat-string}@ fmt, Args&&... args); string vformat(string_view fmt, format_args args); wstring vformat(wstring_view fmt, wformat_args args); @@ -19686,13 +19686,13 @@ wstring vformat(const locale& loc, wstring_view fmt, wformat_args args); template - Out format_to(Out out, @\exposid{format-string}@ fmt, const Args&... args); + Out format_to(Out out, @\exposid{format-string}@ fmt, Args&&... args); template - Out format_to(Out out, @\exposid{wformat-string}@ fmt, const Args&... args); + Out format_to(Out out, @\exposid{wformat-string}@ fmt, Args&&... args); template - Out format_to(Out out, const locale& loc, @\exposid{format-string}@ fmt, const Args&... args); + Out format_to(Out out, const locale& loc, @\exposid{format-string}@ fmt, Args&&... args); template - Out format_to(Out out, const locale& loc, @\exposid{wformat-string}@ fmt, const Args&... args); + Out format_to(Out out, const locale& loc, @\exposid{wformat-string}@ fmt, Args&&... args); template Out vformat_to(Out out, string_view fmt, format_args args); @@ -19709,27 +19709,27 @@ }; template format_to_n_result format_to_n(Out out, iter_difference_t n, - @\exposid{format-string}@ fmt, const Args&... args); + @\exposid{format-string}@ fmt, Args&&... args); template format_to_n_result format_to_n(Out out, iter_difference_t n, - @\exposid{wformat-string}@ fmt, const Args&... args); + @\exposid{wformat-string}@ fmt, Args&&... args); template format_to_n_result format_to_n(Out out, iter_difference_t n, const locale& loc, @\exposid{format-string}@ fmt, - const Args&... args); + Args&&... args); template format_to_n_result format_to_n(Out out, iter_difference_t n, const locale& loc, @\exposid{wformat-string}@ fmt, - const Args&... args); + Args&&... args); template - size_t formatted_size(@\exposid{format-string}@ fmt, const Args&... args); + size_t formatted_size(@\exposid{format-string}@ fmt, Args&&... args); template - size_t formatted_size(@\exposid{wformat-string}@ fmt, const Args&... args); + size_t formatted_size(@\exposid{wformat-string}@ fmt, Args&&... args); template - size_t formatted_size(const locale& loc, @\exposid{format-string}@ fmt, const Args&... args); + size_t formatted_size(const locale& loc, @\exposid{format-string}@ fmt, Args&&... args); template - size_t formatted_size(const locale& loc, @\exposid{wformat-string}@ fmt, const Args&... args); + size_t formatted_size(const locale& loc, @\exposid{wformat-string}@ fmt, Args&&... args); // \ref{format.formatter}, formatter template struct formatter; @@ -19751,10 +19751,10 @@ template @\exposid{format-arg-store}@ - make_format_args(const Args&... fmt_args); + make_format_args(Args&&... fmt_args); template @\exposid{format-arg-store}@ - make_wformat_args(const Args&... args); + make_wformat_args(Args&&... args); // \ref{format.error}, class \tcode{format_error} class format_error; @@ -20513,7 +20513,7 @@ \indexlibraryglobal{format}% \begin{itemdecl} template - string format(@\exposid{format-string}@ fmt, const Args&... args); + string format(@\exposid{format-string}@ fmt, Args&&... args); \end{itemdecl} \begin{itemdescr} @@ -20528,7 +20528,7 @@ \indexlibraryglobal{format}% \begin{itemdecl} template - wstring format(@\exposid{wformat-string}@ fmt, const Args&... args); + wstring format(@\exposid{wformat-string}@ fmt, Args&&... args); \end{itemdecl} \begin{itemdescr} @@ -20543,7 +20543,7 @@ \indexlibraryglobal{format}% \begin{itemdecl} template - string format(const locale& loc, @\exposid{format-string}@ fmt, const Args&... args); + string format(const locale& loc, @\exposid{format-string}@ fmt, Args&&... args); \end{itemdecl} \begin{itemdescr} @@ -20558,7 +20558,7 @@ \indexlibraryglobal{format}% \begin{itemdecl} template - wstring format(const locale& loc, @\exposid{wformat-string}@ fmt, const Args&... args); + wstring format(const locale& loc, @\exposid{wformat-string}@ fmt, Args&&... args); \end{itemdecl} \begin{itemdescr} @@ -20594,7 +20594,7 @@ \indexlibraryglobal{format_to}% \begin{itemdecl} template - Out format_to(Out out, @\exposid{format-string}@ fmt, const Args&... args); + Out format_to(Out out, @\exposid{format-string}@ fmt, Args&&... args); \end{itemdecl} \begin{itemdescr} @@ -20609,7 +20609,7 @@ \indexlibraryglobal{format_to}% \begin{itemdecl} template - Out format_to(Out out, @\exposid{wformat-string}@ fmt, const Args&... args); + Out format_to(Out out, @\exposid{wformat-string}@ fmt, Args&&... args); \end{itemdecl} \begin{itemdescr} @@ -20624,7 +20624,7 @@ \indexlibraryglobal{format_to}% \begin{itemdecl} template - Out format_to(Out out, const locale& loc, @\exposid{format-string}@ fmt, const Args&... args); + Out format_to(Out out, const locale& loc, @\exposid{format-string}@ fmt, Args&&... args); \end{itemdecl} \begin{itemdescr} @@ -20639,7 +20639,7 @@ \indexlibraryglobal{format_to}% \begin{itemdecl} template - Out format_to(Out out, const locale& loc, @\exposid{wformat-string}@ fmt, const Args&... args); + Out format_to(Out out, const locale& loc, @\exposid{wformat-string}@ fmt, Args&&... args); \end{itemdecl} \begin{itemdescr} @@ -20699,18 +20699,18 @@ \begin{itemdecl} template format_to_n_result format_to_n(Out out, iter_difference_t n, - @\exposid{format-string}@ fmt, const Args&... args); + @\exposid{format-string}@ fmt, Args&&... args); template format_to_n_result format_to_n(Out out, iter_difference_t n, - @\exposid{wformat-string}@ fmt, const Args&... args); + @\exposid{wformat-string}@ fmt, Args&&... args); template format_to_n_result format_to_n(Out out, iter_difference_t n, const locale& loc, @\exposid{format-string}@ fmt, - const Args&... args); + Args&&... args); template format_to_n_result format_to_n(Out out, iter_difference_t n, const locale& loc, @\exposid{wformat-string}@ fmt, - const Args&... args); + Args&&... args); \end{itemdecl} \begin{itemdescr} @@ -20731,8 +20731,8 @@ \pnum \expects \tcode{Out} models \tcode{\libconcept{output_iterator}}, and -\tcode{formatter<}$\tcode{T}_i$\tcode{, charT>} -meets the \newoldconcept{Formatter} requirements\iref{formatter.requirements} +\tcode{formatter<}$\tcode{remove_cvref_t, charT>} +meets the \newoldconcept{BasicFormatter} requirements\iref{formatter.requirements} for each $\tcode{T}_i$ in \tcode{Args}. \pnum @@ -20755,13 +20755,13 @@ \indexlibraryglobal{formatted_size}% \begin{itemdecl} template - size_t formatted_size(@\exposid{format-string}@ fmt, const Args&... args); + size_t formatted_size(@\exposid{format-string}@ fmt, Args&&... args); template - size_t formatted_size(@\exposid{wformat-string}@ fmt, const Args&... args); + size_t formatted_size(@\exposid{wformat-string}@ fmt, Args&&... args); template - size_t formatted_size(const locale& loc, @\exposid{format-string}@ fmt, const Args&... args); + size_t formatted_size(const locale& loc, @\exposid{format-string}@ fmt, Args&&... args); template - size_t formatted_size(const locale& loc, @\exposid{wformat-string}@ fmt, const Args&... args); + size_t formatted_size(const locale& loc, @\exposid{wformat-string}@ fmt, Args&&... args); \end{itemdecl} \begin{itemdescr} @@ -20770,8 +20770,8 @@ \pnum \expects -\tcode{formatter<}$\tcode{T}_i$\tcode{, charT>} -meets the \newoldconcept{Formatter} requirements\iref{formatter.requirements} +\tcode{formatter<}$\tcode{remove_cvref_t, charT>} +meets the \newoldconcept{BasicFormatter} requirements\iref{formatter.requirements} for each $\tcode{T}_i$ in \tcode{Args}. \pnum @@ -20791,7 +20791,7 @@ \rSec3[formatter.requirements]{Formatter requirements} \pnum -A type \tcode{F} meets the \defnnewoldconcept{Formatter} requirements if: +A type \tcode{F} meets the \defnnewoldconcept{BasicFormatter} requirements if: \begin{itemize} \item it meets the @@ -20807,14 +20807,20 @@ it is swappable\iref{swappable.requirements} for lvalues, and \item -the expressions shown in \tref{formatter} are valid and +the expressions shown in \tref{formatter.basic} are valid and have the indicated semantics. \end{itemize} +\pnum +A type \tcode{F} meets the \defnnewoldconcept{Formatter} requirements +if it meets the \newoldconcept{BasicFormatter} requirements and +the expressions shown in \tref{formatter} are valid and +have the indicated semantics. + \pnum Given character type \tcode{charT}, output iterator type \tcode{Out}, and formatting argument type \tcode{T}, -in \tref{formatter}: +in \tref{formatter.basic} and \tref{formatter}: \begin{itemize} \item \tcode{f} is a value of type \tcode{F}, \item \tcode{u} is an lvalue of type \tcode{T}, @@ -20832,7 +20838,7 @@ \tcode{pc.begin() == pc.end()} or \tcode{*pc.begin() == '\}'}. -\begin{concepttable}{\newoldconcept{Formatter} requirements}{formatter} +\begin{concepttable}{\newoldconcept{BasicFormatter} requirements}{formatter.basic} {p{1.2in}p{1in}p{2.9in}} \topline \hdstyle{Expression} & \hdstyle{Return type} & \hdstyle{Requirement} \\ \capsep @@ -20850,10 +20856,28 @@ Stores the parsed format specifiers in \tcode{*this} and returns an iterator past the end of the parsed range. \\ \rowsep +\tcode{f.format(u, fc)} & +\tcode{FC::iterator} & +Formats \tcode{u} according to the specifiers stored in \tcode{*this}, +writes the output to \tcode{fc.out()}, and +returns an iterator past the end of the output range. +The output shall only depend on +\tcode{u}, +\tcode{fc.locale()}, +\tcode{fc.arg(n)} for any value \tcode{n} of type \tcode{size_t}, +and the range \range{pc.begin()}{pc.end()} +from the last call to \tcode{f.parse(pc)}. +\\ +\end{concepttable} + +\begin{concepttable}{\newoldconcept{Formatter} requirements}{formatter} +{p{1.2in}p{1in}p{2.9in}} +\topline +\hdstyle{Expression} & \hdstyle{Return type} & \hdstyle{Requirement} \\ \capsep \tcode{f.format(t, fc)} & \tcode{FC::iterator} & Formats \tcode{t} according to the specifiers stored in \tcode{*this}, -writes the output to \tcode{fc.out()} and +writes the output to \tcode{fc.out()}, and returns an iterator past the end of the output range. The output shall only depend on \tcode{t}, @@ -20881,10 +20905,6 @@ Let \tcode{charT} be either \tcode{char} or \keyword{wchar_t}. Each specialization of \tcode{formatter} is either enabled or disabled, as described below. -\begin{note} -Enabled specializations meet the \newoldconcept{Formatter} requirements, -and disabled specializations do not. -\end{note} Each header that declares the template \tcode{formatter} provides the following enabled specializations: \begin{itemize} @@ -20958,6 +20978,7 @@ \pnum If the library provides an explicit or partial specialization of \tcode{formatter}, that specialization is enabled +and meets the \newoldconcept{Formatter} requirements except as noted otherwise. \pnum @@ -20973,7 +20994,7 @@ \pnum An enabled specialization \tcode{formatter} meets the -\newoldconcept{Formatter} requirements\iref{formatter.requirements}. +\newoldconcept{BasicFormatter} requirements\iref{formatter.requirements}. \begin{example} \begin{codeblock} #include @@ -21309,7 +21330,7 @@ const char_type*, basic_string_view, const void*, handle> value; // \expos - template explicit basic_format_arg(const T& v) noexcept; // \expos + template explicit basic_format_arg(T&& v) noexcept; // \expos explicit basic_format_arg(float n) noexcept; // \expos explicit basic_format_arg(double n) noexcept; // \expos explicit basic_format_arg(long double n) noexcept; // \expos @@ -21356,7 +21377,7 @@ \end{itemdescr} \begin{itemdecl} -template explicit basic_format_arg(const T& v) noexcept; +template explicit basic_format_arg(T&& v) noexcept; \end{itemdecl} \begin{itemdescr} @@ -21364,16 +21385,16 @@ \constraints The template specialization \begin{codeblock} -typename Context::template formatter_type +typename Context::template formatter_type> \end{codeblock} -meets the \newoldconcept{Formatter} requirements\iref{formatter.requirements}. +meets the \newoldconcept{BasicFormatter} requirements\iref{formatter.requirements}. The extent to which an implementation determines that -the specialization meets the \newoldconcept{Formatter} requirements +the specialization meets the \newoldconcept{BasicFormatter} requirements is unspecified, except that as a minimum the expression \begin{codeblock} -typename Context::template formatter_type() - .format(declval(), declval()) +typename Context::template formatter_type>() + .format(declval(), declval()) \end{codeblock} shall be well-formed when treated as an unevaluated operand. @@ -21518,7 +21539,7 @@ void (*format_)(basic_format_parse_context&, Context&, const void*); // \expos - template explicit handle(const T& val) noexcept; // \expos + template explicit handle(T&& val) noexcept; // \expos friend class basic_format_arg; // \expos @@ -21530,10 +21551,28 @@ \indexlibraryctor{basic_format_arg::handle}% \begin{itemdecl} -template explicit handle(const T& val) noexcept; +template explicit handle(T&& val) noexcept; \end{itemdecl} \begin{itemdescr} +\pnum +Let +\begin{itemize} +\item +\tcode{TD} be \tcode{remove_cvref_t}, +\item +\exposid{const-formattable} be \tcode{true} if +\tcode{typename Context::template formatter_type()\newline .format(declval(), declval())} is well-formed, otherwise \tcode{false}, +\item +\tcode{TQ} be \tcode{const TD} if \exposid{const-formattable} is \tcode{true} +and \tcode{TD} otherwise. +\end{itemize} + +\pnum +\mandates +\tcode{\exposid{const-formattable} || !is_const_v>} is +\tcode{true}. + \pnum \effects Initializes @@ -21542,9 +21581,10 @@ \begin{codeblock} [](basic_format_parse_context& parse_ctx, Context& format_ctx, const void* ptr) { - typename Context::template formatter_type f; + typename Context::template formatter_type f; parse_ctx.advance_to(f.parse(parse_ctx)); - format_ctx.advance_to(f.format(*static_cast(ptr), format_ctx)); + format_ctx.advance_to(f.format(*const_cast(static_cast(ptr)), + format_ctx)); } \end{codeblock} \end{itemdescr} @@ -21589,7 +21629,7 @@ \indexlibraryglobal{make_format_args}% \begin{itemdecl} template - @\exposid{format-arg-store}@ make_format_args(const Args&... fmt_args); + @\exposid{format-arg-store}@ make_format_args(Args&&... fmt_args); \end{itemdecl} \begin{itemdescr} @@ -21597,7 +21637,7 @@ \expects The type \tcode{typename Context::template formatter_type<}$\tcode{T}_i$\tcode{>} -meets the \newoldconcept{Formatter} requirements\iref{formatter.requirements} +meets the \newoldconcept{BasicFormatter} requirements\iref{formatter.requirements} for each $\tcode{T}_i$ in \tcode{Args}. \pnum @@ -21610,7 +21650,7 @@ \indexlibraryglobal{make_wformat_args}% \begin{itemdecl} template - @\exposid{format-arg-store}@ make_wformat_args(const Args&... args); + @\exposid{format-arg-store}@ make_wformat_args(Args&&... args); \end{itemdecl} \begin{itemdescr} From b094cb62a059fe19b632ec22c37b3a306fa897e3 Mon Sep 17 00:00:00 2001 From: Jens Maurer Date: Mon, 18 Oct 2021 12:34:19 +0200 Subject: [PATCH 2/2] [diff.cpp20.utilities] Rephrase to avoid undefined term 'const-iterable' --- source/compatibility.tex | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/source/compatibility.tex b/source/compatibility.tex index 76b01589e8..6c88c853a6 100644 --- a/source/compatibility.tex +++ b/source/compatibility.tex @@ -81,7 +81,9 @@ Signature changes: \tcode{format}, \tcode{format_to}, \tcode{format_to_n}, \tcode{formatted_size}. \rationale -Enable formatting of views that are neither const-iterable nor copyable. +Enable formatting of views +that do not support iteration when const-qualified and +are not copyable. \effect Valid \CppXX{} code that passes bit fields to formatting functions may become ill-formed. For example: