Section: 28.5.5 [format.functions] Status: C++20 Submitter: Great Britain Opened: 2019-11-17 Last modified: 2021-02-25
Priority: Not Prioritized
View all other issues in [format.functions].
View all issues with C++20 status.
Discussion:
Addresses GB 229
Formatting functions don't allow throwing on incorrect arguments.
std::format
is only allowed to throw if fmt
is not a format string, but the
intention is it also throws for errors during formatting, e.g. there are fewer arguments than
required by the format string.
Proposed change:
Allow exceptions even when the format string is valid. Possibly state the Effects: more precisely.
Victor Zverovich:
LEWG approved resolution of this NB comment as an LWG issue. Previous resolution [SUPERSEDED]:This wording is relative to N4835.
[Drafting Note: Depending on whether LWG 3336's wording has been accepted when this issue's wording has been accepted, two mutually exclusive options are prepared, depicted below by Option A and Option B, respectively.]
Option A (LWG 3336 has been accepted)
Change 28.5.2.1 [format.string.general] as follows:
-1- A format string for arguments
-2- The arg-id field specifies the index of the argument inargs
is a (possibly empty) sequence of replacement fields, escape sequences, and characters other than{
and}
. […]args
whose value is to be formatted and inserted into the output instead of the replacement field. If there is no argument with the index arg-id inargs
, the string is not a format string. The optional format-specifier field explicitly specifies a format for the replacement value. […] -5- The format-spec field contains format specifications that define how the value should be presented. Each type can define its own interpretation of the format-spec field. If format-spec doesn't conform to the format specifications for the argument inargs
referred to by arg-id, the string is not a format string. […]Before 28.5.5 [format.functions] insert a new sub-clause as indicated:
20.20.? Error reporting [format.err.report]
-?- Formatting functions throw exceptions to report formatting and other errors. They throwformat_error
if an argumentfmt
is passed that is not a format string for argumentsargs
and propagate exceptions thrown byformatter
specializations and iterator operations. Failure to allocate storage is reported by throwing an exception as described in 16.4.6.13 [res.on.exception.handling].Modify 28.5.5 [format.functions] as indicated:
string vformat(string_view fmt, format_args args); 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);[…]-6- […]
-7- Throws:As specified in 28.5.3 [format.err.report].format_error
iffmt
is not a format stringtemplate<class Out> Out vformat_to(Out out, string_view fmt, format_args_t<Out, char> args); template<class Out> Out vformat_to(Out out, wstring_view fmt, format_args_t<Out, wchar_t> args); template<class Out> Out vformat_to(Out out, const locale& loc, string_view fmt, format_args_t<Out, char> args); template<class Out> Out vformat_to(Out out, const locale& loc, wstring_view fmt, format_args_t<Out, wchar_t> args);[…][…]
-15- Throws:As specified in 28.5.3 [format.err.report].format_error
iffmt
is not a format stringtemplate<class Out, class... Args> format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n, string_view fmt, const Args&... args); template<class Out, class... Args> format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n, wstring_view fmt, const Args&... args); template<class Out, class... Args> format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n, const locale& loc, string_view fmt, const Args&... args); template<class Out, class... Args> format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n, const locale& loc, wstring_view fmt, const Args&... args);[…][…]
-21- Throws:As specified in 28.5.3 [format.err.report].format_error
iffmt
is not a format stringtemplate<class... Args> size_t formatted_size(string_view fmt, const Args&... args); template<class... Args> size_t formatted_size(wstring_view fmt, const Args&... args); template<class... Args> size_t formatted_size(const locale& loc, string_view fmt, const Args&... args); template<class... Args> size_t formatted_size(const locale& loc, wstring_view fmt, const Args&... args);[…]
-25- Throws:As specified in 28.5.3 [format.err.report].format_error
iffmt
is not a format stringOption B (LWG 3336 has not been accepted)
Change 28.5.2.1 [format.string.general] as follows:
-1- A format string for arguments
-2- The arg-id field specifies the index of the argument inargs
is a (possibly empty) sequence of replacement fields, escape sequences, and characters other than{
and}
. […]args
whose value is to be formatted and inserted into the output instead of the replacement field. If there is no argument with the index arg-id inargs
, the string is not a format string. The optional format-specifier field explicitly specifies a format for the replacement value. […] -5- The format-spec field contains format specifications that define how the value should be presented. Each type can define its own interpretation of the format-spec field. If format-spec doesn't conform to the format specifications for the argument inargs
referred to by arg-id, the string is not a format string. […]Modify 28.5.5 [format.functions] as indicated:
string vformat(string_view fmt, format_args args); 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);[…]-6- […]
-7- Throws:format_error
iffmt
is not a format string forargs
.template<class Out> Out vformat_to(Out out, string_view fmt, format_args_t<Out, char> args); template<class Out> Out vformat_to(Out out, wstring_view fmt, format_args_t<Out, wchar_t> args); template<class Out> Out vformat_to(Out out, const locale& loc, string_view fmt, format_args_t<Out, char> args); template<class Out> Out vformat_to(Out out, const locale& loc, wstring_view fmt, format_args_t<Out, wchar_t> args);[…][…]
-15- Throws:format_error
iffmt
is not a format string forargs
.template<class Out, class... Args> format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n, string_view fmt, const Args&... args); template<class Out, class... Args> format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n, wstring_view fmt, const Args&... args); template<class Out, class... Args> format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n, const locale& loc, string_view fmt, const Args&... args); template<class Out, class... Args> format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n, const locale& loc, wstring_view fmt, const Args&... args);[…][…]
-21- Throws:format_error
iffmt
is not a format string forargs
.template<class... Args> size_t formatted_size(string_view fmt, const Args&... args); template<class... Args> size_t formatted_size(wstring_view fmt, const Args&... args); template<class... Args> size_t formatted_size(const locale& loc, string_view fmt, const Args&... args); template<class... Args> size_t formatted_size(const locale& loc, wstring_view fmt, const Args&... args);[…]
-25- Throws:format_error
iffmt
is not a format string forargs
.
[2020-02-12, Prague; LWG discussion]
Option A is the only one we look at to resolve LWG 3336 as well. During the discussions some wording refinements have been suggested that are integrated below.
Proposed resolution:
This wording is relative to N4849.
Change 28.5.2.1 [format.string.general] as follows:
-1- A format string for arguments
-2- The arg-id field specifies the index of the argument inargs
is a (possibly empty) sequence of replacement fields, escape sequences, and characters other than{
and}
. […]args
whose value is to be formatted and inserted into the output instead of the replacement field. If there is no argument with the index arg-id inargs
, the string is not a format string forargs
. The optional format-specifier field explicitly specifies a format for the replacement value. […] -5- The format-spec field contains format specifications that define how the value should be presented. Each type can define its own interpretation of the format-spec field. If format-spec does not conform to the format specifications for the argument type referred to by arg-id, the string is not a format string forargs
. […]
Before 28.5.5 [format.functions] insert a new sub-clause as indicated:
20.20.? Error reporting [format.err.report]
-?- Formatting functions throwformat_error
if an argumentfmt
is passed that is not a format string forargs
. They propagate exceptions thrown by operations offormatter
specializations and iterators. Failure to allocate storage is reported by throwing an exception as described in 16.4.6.13 [res.on.exception.handling].
Modify 28.5.5 [format.functions] as indicated:
string vformat(string_view fmt, format_args args); 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);[…]-6- […]
-7- Throws:As specified in 28.5.3 [format.err.report].format_error
iffmt
is not a format stringtemplate<class Out> Out vformat_to(Out out, string_view fmt, format_args_t<Out, char> args); template<class Out> Out vformat_to(Out out, wstring_view fmt, format_args_t<Out, wchar_t> args); template<class Out> Out vformat_to(Out out, const locale& loc, string_view fmt, format_args_t<Out, char> args); template<class Out> Out vformat_to(Out out, const locale& loc, wstring_view fmt, format_args_t<Out, wchar_t> args);[…][…]
-15- Throws:As specified in 28.5.3 [format.err.report].format_error
iffmt
is not a format stringtemplate<class Out, class... Args> format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n, string_view fmt, const Args&... args); template<class Out, class... Args> format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n, wstring_view fmt, const Args&... args); template<class Out, class... Args> format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n, const locale& loc, string_view fmt, const Args&... args); template<class Out, class... Args> format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n, const locale& loc, wstring_view fmt, const Args&... args);[…][…]
-21- Throws:As specified in 28.5.3 [format.err.report].format_error
iffmt
is not a format stringtemplate<class... Args> size_t formatted_size(string_view fmt, const Args&... args); template<class... Args> size_t formatted_size(wstring_view fmt, const Args&... args); template<class... Args> size_t formatted_size(const locale& loc, string_view fmt, const Args&... args); template<class... Args> size_t formatted_size(const locale& loc, wstring_view fmt, const Args&... args);[…]
-25- Throws:As specified in 28.5.3 [format.err.report].format_error
iffmt
is not a format string