diff --git a/source/strings.tex b/source/strings.tex index 9e1e9481b8..81643f6617 100644 --- a/source/strings.tex +++ b/source/strings.tex @@ -1927,12 +1927,12 @@ float stof(const string& str, size_t* idx = nullptr); double stod(const string& str, size_t* idx = nullptr); long double stold(const string& str, size_t* idx = nullptr); - string to_string(int val); - string to_string(unsigned val); - string to_string(long val); - string to_string(unsigned long val); - string to_string(long long val); - string to_string(unsigned long long val); + constexpr string to_string(int val); + constexpr string to_string(unsigned val); + constexpr string to_string(long val); + constexpr string to_string(unsigned long val); + constexpr string to_string(long long val); + constexpr string to_string(unsigned long long val); string to_string(float val); string to_string(double val); string to_string(long double val); @@ -1945,12 +1945,12 @@ float stof(const wstring& str, size_t* idx = nullptr); double stod(const wstring& str, size_t* idx = nullptr); long double stold(const wstring& str, size_t* idx = nullptr); - wstring to_wstring(int val); - wstring to_wstring(unsigned val); - wstring to_wstring(long val); - wstring to_wstring(unsigned long val); - wstring to_wstring(long long val); - wstring to_wstring(unsigned long long val); + constexpr wstring to_wstring(int val); + constexpr wstring to_wstring(unsigned val); + constexpr wstring to_wstring(long val); + constexpr wstring to_wstring(unsigned long val); + constexpr wstring to_wstring(long long val); + constexpr wstring to_wstring(unsigned long long val); wstring to_wstring(float val); wstring to_wstring(double val); wstring to_wstring(long double val); @@ -5273,12 +5273,12 @@ \indexlibraryglobal{to_string}% \begin{itemdecl} -string to_string(int val); -string to_string(unsigned val); -string to_string(long val); -string to_string(unsigned long val); -string to_string(long long val); -string to_string(unsigned long long val); +constexpr string to_string(int val); +constexpr string to_string(unsigned val); +constexpr string to_string(long val); +constexpr string to_string(unsigned long val); +constexpr string to_string(long long val); +constexpr string to_string(unsigned long long val); string to_string(float val); string to_string(double val); string to_string(long double val); @@ -5360,12 +5360,12 @@ \indexlibraryglobal{to_wstring}% \begin{itemdecl} -wstring to_wstring(int val); -wstring to_wstring(unsigned val); -wstring to_wstring(long val); -wstring to_wstring(unsigned long val); -wstring to_wstring(long long val); -wstring to_wstring(unsigned long long val); +constexpr wstring to_wstring(int val); +constexpr wstring to_wstring(unsigned val); +constexpr wstring to_wstring(long val); +constexpr wstring to_wstring(unsigned long val); +constexpr wstring to_wstring(long long val); +constexpr wstring to_wstring(unsigned long long val); wstring to_wstring(float val); wstring to_wstring(double val); wstring to_wstring(long double val); diff --git a/source/support.tex b/source/support.tex index c6929d58ff..a7ccc3ea0a 100644 --- a/source/support.tex +++ b/source/support.tex @@ -631,6 +631,7 @@ // also in \libheader{exception}, \libheader{stdexcept}, \libheader{expected}, \libheader{optional}, \libheader{variant}, and \libheader{format} #define @\defnlibxname{cpp_lib_constexpr_flat_map}@ 202502L // also in \libheader{flat_map} #define @\defnlibxname{cpp_lib_constexpr_flat_set}@ 202502L // also in \libheader{flat_set} +#define @\defnlibxname{cpp_lib_constexpr_format}@ 202511L // also in \libheader{format} #define @\defnlibxname{cpp_lib_constexpr_forward_list}@ 202502L // also in \libheader{forward_list} #define @\defnlibxname{cpp_lib_constexpr_functional}@ 201907L // freestanding, also in \libheader{functional} #define @\defnlibxname{cpp_lib_constexpr_inplace_vector}@ 202502L // also in \libheader{inplace_vector} diff --git a/source/text.tex b/source/text.tex index 58d6cce5b0..e4abbc2c6e 100644 --- a/source/text.tex +++ b/source/text.tex @@ -5752,12 +5752,14 @@ private: basic_string_view @\exposid{str}@; // \expos public: - @\exposid{runtime-format-string}@(basic_string_view s) noexcept : @\exposid{str}@(s) {} + constexpr @\exposid{runtime-format-string}@(basic_string_view s) noexcept : @\exposid{str}@(s) {} @\exposid{runtime-format-string}@(const @\exposid{runtime-format-string}@&) = delete; @\exposid{runtime-format-string}@& operator=(const @\exposid{runtime-format-string}@&) = delete; }; - @\exposid{runtime-format-string}@ runtime_format(string_view fmt) noexcept { return fmt; } - @\exposid{runtime-format-string}@ runtime_format(wstring_view fmt) noexcept { return fmt; } + constexpr @\exposid{runtime-format-string}@ + runtime_format(string_view fmt) noexcept { return fmt; } + constexpr @\exposid{runtime-format-string}@ + runtime_format(wstring_view fmt) noexcept { return fmt; } template using @\libglobal{format_string}@ = basic_format_string...>; @@ -5766,32 +5768,32 @@ // \ref{format.functions}, formatting functions template - string format(format_string fmt, Args&&... args); + constexpr string format(format_string fmt, Args&&... args); template - wstring format(wformat_string fmt, Args&&... args); + constexpr wstring format(wformat_string fmt, Args&&... args); template string format(const locale& loc, format_string fmt, Args&&... args); template wstring format(const locale& loc, wformat_string fmt, Args&&... args); - string vformat(string_view fmt, format_args args); - wstring vformat(wstring_view fmt, wformat_args args); + constexpr string vformat(string_view fmt, format_args args); + constexpr wstring vformat(wstring_view fmt, wformat_args args); string vformat(const locale& loc, string_view fmt, format_args args); wstring vformat(const locale& loc, wstring_view fmt, wformat_args args); template - Out format_to(Out out, format_string fmt, Args&&... args); + constexpr Out format_to(Out out, format_string fmt, Args&&... args); template - Out format_to(Out out, wformat_string fmt, Args&&... args); + constexpr Out format_to(Out out, wformat_string fmt, Args&&... args); template Out format_to(Out out, const locale& loc, format_string fmt, Args&&... args); template Out format_to(Out out, const locale& loc, wformat_string fmt, Args&&... args); template - Out vformat_to(Out out, string_view fmt, format_args args); + constexpr Out vformat_to(Out out, string_view fmt, format_args args); template - Out vformat_to(Out out, wstring_view fmt, wformat_args args); + constexpr Out vformat_to(Out out, wstring_view fmt, wformat_args args); template Out vformat_to(Out out, const locale& loc, string_view fmt, format_args args); template @@ -5802,11 +5804,13 @@ iter_difference_t size; }; template - format_to_n_result format_to_n(Out out, iter_difference_t n, - format_string fmt, Args&&... args); + constexpr format_to_n_result format_to_n(Out out, iter_difference_t n, + format_string fmt, + Args&&... args); template - format_to_n_result format_to_n(Out out, iter_difference_t n, - wformat_string fmt, Args&&... args); + constexpr format_to_n_result format_to_n(Out out, iter_difference_t n, + wformat_string fmt, + Args&&... args); template format_to_n_result format_to_n(Out out, iter_difference_t n, const locale& loc, format_string fmt, @@ -5817,9 +5821,9 @@ Args&&... args); template - size_t formatted_size(format_string fmt, Args&&... args); + constexpr size_t formatted_size(format_string fmt, Args&&... args); template - size_t formatted_size(wformat_string fmt, Args&&... args); + constexpr size_t formatted_size(wformat_string fmt, Args&&... args); template size_t formatted_size(const locale& loc, format_string fmt, Args&&... args); template @@ -5895,10 +5899,10 @@ template class @\exposidnc{format-arg-store}@; // \expos template - @\exposid{format-arg-store}@ + constexpr @\exposid{format-arg-store}@ make_format_args(Args&... fmt_args); template - @\exposid{format-arg-store}@ + constexpr @\exposid{format-arg-store}@ make_wformat_args(Args&... args); // \ref{format.error}, class \tcode{format_error} @@ -6381,6 +6385,8 @@ the \defnx{locale-specific form}{locale-specific form!format string}. The \tcode{L} option is only valid for arithmetic types, and its effect depends upon the type. +A call to \tcode{format} on a given formatter specialization +is not a constant subexpression if the locale-specific form is specified. \begin{itemize} \item For integral types, the locale-specific form @@ -6669,7 +6675,7 @@ public: template consteval basic_format_string(const T& s); - basic_format_string(@\exposid{runtime-format-string}@ s) noexcept : str(s.@\exposid{str}@) {} + constexpr basic_format_string(@\exposid{runtime-format-string}@ s) noexcept : str(s.@\exposid{str}@) {} constexpr basic_string_view get() const noexcept { return @\exposid{str}@; } }; @@ -6698,6 +6704,12 @@ \rSec2[format.functions]{Formatting functions} +\pnum +A call to any of the functions defined in this subclause +is a constant subexpression only if +each of the used \tcode{formatter} specializations +is a constexpr-enabled specialization\iref{format.formatter.spec}. + \pnum In the description of the functions, operator \tcode{+} is used for some of the iterator categories for which it does not have to be defined. @@ -7148,12 +7160,14 @@ which modifies the state of the \tcode{formatter} to be as if the type of the \fmtgrammarterm{std-format-spec} parsed by the last call to \tcode{parse} were \tcode{?}. +A \defn{constexpr-enabled} specialization of \tcode{formatter} +has its \tcode{format} member function declared \tcode{constexpr}. Each header that declares the template \tcode{formatter} provides the following enabled specializations: \begin{itemize} \item \indexlibrary{\idxcode{formatter}!specializations!character types}% -The debug-enabled specializations +The debug-enabled and constexpr-enabled specializations \begin{codeblock} template<> struct formatter; template<> struct formatter; @@ -7163,7 +7177,7 @@ \item \indexlibrary{\idxcode{formatter}!specializations!string types}% For each \tcode{charT}, -the debug-enabled string type specializations +the debug-enabled and constexpr-enabled string type specializations \begin{codeblock} template<> struct formatter; template<> struct formatter; @@ -7175,27 +7189,37 @@ \end{codeblock} \item -\indexlibrary{\idxcode{formatter}!specializations!arithmetic types}% +\indexlibrary{\idxcode{formatter}!specializations!integer types}% +For each \tcode{charT}, +for each \tcode{IntegerT} that is either +a signed or unsigned integer type or \tcode{bool}, +a constexpr-enabled specialization +\begin{codeblock} +template<> struct formatter; +\end{codeblock} + +\item +\indexlibrary{\idxcode{formatter}!specializations!floating-point types}% For each \tcode{charT}, -for each cv-unqualified arithmetic type \tcode{ArithmeticT} -other than -\tcode{char}, -\keyword{wchar_t}, -\keyword{char8_t}, -\keyword{char16_t}, or -\keyword{char32_t}, +for each \tcode{FloatingT} that is a cv-unqualified floating-point type, a specialization \begin{codeblock} -template<> struct formatter; +template<> struct formatter; \end{codeblock} \item \indexlibrary{\idxcode{formatter}!specializations!pointer types}% \indexlibrary{\idxcode{formatter}!specializations!\idxcode{nullptr_t}}% For each \tcode{charT}, -the pointer type specializations +the constexpr-enabled pointer type specialization \begin{codeblock} template<> struct formatter; +\end{codeblock} + +\item +For each \tcode{charT}, +the pointer type specializations +\begin{codeblock} template<> struct formatter; template<> struct formatter; \end{codeblock} @@ -7696,11 +7720,11 @@ using char_type = charT; template using formatter_type = formatter; - basic_format_arg arg(size_t id) const noexcept; + constexpr basic_format_arg arg(size_t id) const noexcept; std::locale locale(); - iterator out(); - void advance_to(iterator it); + constexpr iterator out(); + constexpr void advance_to(iterator it); }; } \end{codeblock} @@ -7916,7 +7940,7 @@ template requires @\libconcept{formattable}@, charT> && @\libconcept{same_as}@>, T> - typename FormatContext::iterator + constexpr typename FormatContext::iterator format(R&& r, FormatContext& ctx) const; }; } @@ -8150,7 +8174,7 @@ parse(ParseContext& ctx); template - typename FormatContext::iterator + constexpr typename FormatContext::iterator format(@\exposid{maybe-const-r}@& elems, FormatContext& ctx) const; }; } @@ -8226,7 +8250,7 @@ parse(ParseContext& ctx); template - typename FormatContext::iterator + constexpr typename FormatContext::iterator format(@\exposid{maybe-const-map}@& r, FormatContext& ctx) const; }; } @@ -8305,7 +8329,7 @@ parse(ParseContext& ctx); template - typename FormatContext::iterator + constexpr typename FormatContext::iterator format(@\exposid{maybe-const-set}@& r, FormatContext& ctx) const; }; } @@ -8368,7 +8392,7 @@ parse(ParseContext& ctx); template - typename FormatContext::iterator + constexpr typename FormatContext::iterator format(@\seebelow@& str, FormatContext& ctx) const; }; } @@ -8440,17 +8464,17 @@ const char_type*, basic_string_view, const void*, handle> value; // \expos - template explicit basic_format_arg(T& v) noexcept; // \expos + template constexpr explicit basic_format_arg(T& v) noexcept; // \expos public: - basic_format_arg() noexcept; + constexpr basic_format_arg() noexcept; - explicit operator bool() const noexcept; + constexpr explicit operator bool() const noexcept; template - decltype(auto) visit(this basic_format_arg arg, Visitor&& vis); + constexpr decltype(auto) visit(this basic_format_arg arg, Visitor&& vis); template - R visit(this basic_format_arg arg, Visitor&& vis); + constexpr R visit(this basic_format_arg arg, Visitor&& vis); }; } \end{codeblock} @@ -8589,14 +8613,14 @@ namespace std { template class basic_format_arg::handle { - const void* ptr_; // \expos + const void* ptr_; // \expos void (*format_)(basic_format_parse_context&, - Context&, const void*); // \expos + Context&, const void*); // \expos - template explicit handle(T& val) noexcept; // \expos + template constexpr explicit handle(T& val) noexcept; // \expos public: - void format(basic_format_parse_context&, Context& ctx) const; + constexpr void format(basic_format_parse_context&, Context& ctx) const; }; } \end{codeblock} @@ -8708,9 +8732,9 @@ public: template - basic_format_args(const @\exposid{format-arg-store}@& store) noexcept; + constexpr basic_format_args(const @\exposid{format-arg-store}@& store) noexcept; - basic_format_arg get(size_t i) const noexcept; + constexpr basic_format_arg get(size_t i) const noexcept; }; template @@ -8782,7 +8806,7 @@ parse(ParseContext& ctx); template - typename FormatContext::iterator + constexpr typename FormatContext::iterator format(@\seebelow@& elems, FormatContext& ctx) const; };