Difference between revisions of "cpp/utility/format/make format args"
(Example: +) |
m (→Example: fmt) |
||
(26 intermediate revisions by 10 users not shown) | |||
Line 3: | Line 3: | ||
{{dcl begin}} | {{dcl begin}} | ||
− | {{dcl header | format}} | + | {{dcl header|format}} |
− | {{dcl | num=1 | since=c++20 |1= | + | {{dcl|num=1|since=c++20|1= |
− | template<class Context = std::format_context, class... Args> | + | template< class Context = std::format_context, class... Args > |
− | /*format-arg-store*/<Context, Args...> make_format_args( | + | /*format-arg-store*/<Context, Args...> |
+ | make_format_args( Args&... args ); | ||
}} | }} | ||
− | {{dcl | num=2 | since=c++20 |1= | + | {{dcl|num=2|since=c++20|1= |
− | template<class... Args> | + | template< class... Args > |
− | /*format-arg-store*/<std::wformat_context, Args...> make_wformat_args( | + | /*format-arg-store*/<std::wformat_context, Args...> |
+ | make_wformat_args( Args&... args ); | ||
}} | }} | ||
{{dcl end}} | {{dcl end}} | ||
Line 16: | Line 18: | ||
Returns an object that stores an array of formatting arguments and can be implicitly converted to {{lc|std::basic_format_args|std::basic_format_args<Context>}}. | Returns an object that stores an array of formatting arguments and can be implicitly converted to {{lc|std::basic_format_args|std::basic_format_args<Context>}}. | ||
− | The behavior is undefined if {{c|typename Context::template formatter_type<Ti>}} does not meet the {{named req| | + | The behavior is undefined if {{c|typename Context::template formatter_type<std::remove_const_t<Ti>>}} does not meet the {{named req|BasicFormatter}} requirements for any {{tt|Ti}} in {{tt|Args}}. |
+ | |||
+ | The program is ill-formed if for any type {{tt|Ti}} in {{tt|Args}}, {{tt|Ti}} does not satisfy {{lti|cpp/utility/format/formattable|__formattable_with}}{{c/core|<Context>}}. | ||
+ | |||
+ | @2@ Equivalent to {{c|return std::make_format_args<std::wformat_context>(args...);}}. | ||
===Parameters=== | ===Parameters=== | ||
{{par begin}} | {{par begin}} | ||
− | {{par | args... | values to be used as formatting arguments}} | + | {{par|args...|values to be used as formatting arguments}} |
{{par end}} | {{par end}} | ||
===Returns=== | ===Returns=== | ||
An object that holds the formatting arguments. | An object that holds the formatting arguments. | ||
+ | |||
+ | For each argument {{tt|t}} of type {{tt|T}}, let {{tt|TD}} be {{c|std::remove_const_t<std::remove_reference_t<T>>}}. The corresponding {{lc|std::basic_format_arg}} in the result is determined as below: | ||
+ | * if {{tt|TD}} is {{c/core|bool}} or {{tt|Context::char_type}}, the {{lc|std::basic_format_arg}} stores {{c|t}}; | ||
+ | * otherwise, if {{tt|TD}} is {{c/core|char}} and {{tt|Context::char_type}} is {{c/core|wchar_t}}, the {{lc|std::basic_format_arg}} stores {{c|static_cast<wchar_t>(static_cast<unsigned char>(t))}}; | ||
+ | * otherwise, if {{tt|TD}} is a signed integer type whose size is not greater than {{c/core|int}}, the {{lc|std::basic_format_arg}} stores {{c|static_cast<int>(t)}}; | ||
+ | * otherwise, if {{tt|TD}} is a unsigned integer type whose size is not greater than {{c/core|unsigned int}}, the {{lc|std::basic_format_arg}} stores {{c|static_cast<unsigned int>(t)}}; | ||
+ | * otherwise, if {{tt|TD}} is a signed integer type whose size is not greater than {{c/core|long long}}, the {{lc|std::basic_format_arg}} stores {{c|static_cast<long long>(t)}}; | ||
+ | * otherwise, if {{tt|TD}} is a unsigned integer type whose size is not greater than {{c/core|unsigned long long}}, the {{lc|std::basic_format_arg}} stores {{c|static_cast<unsigned long long>(t)}}; | ||
+ | * otherwise, if {{tt|TD}} is {{c/core|float}}, {{c/core|double}}, or {{c/core|long double}}, the {{lc|std::basic_format_arg}} stores {{c|t}}; | ||
+ | * otherwise, if {{tt|TD}} is a {{lc|std::basic_string_view}} or {{lc|std::basic_string}} specialization and {{tt|TD::char_type}} is {{tt|Context::char_type}}, the {{lc|std::basic_format_arg}} stores {{c|std::basic_string_view<Context::char_type>(t.data(), t.size())}}; | ||
+ | * otherwise, if {{c|std::decay_t<TD>}} is {{c|Context::char_type*}} or {{c|const Context::char_type*}}, the {{lc|std::basic_format_arg}} stores {{c|static_cast<const Context::char_type*>(t)}}; | ||
+ | * otherwise, if {{c|std::is_void_v<std::remove_pointer_t<TD>>}} is {{c|true}} or {{c|std::is_null_pointer_v<TD>}} is {{c|true}}, the {{lc|std::basic_format_arg}} stores {{c|static_cast<const void*>(t)}}; | ||
+ | * otherwise, the {{lc|std::basic_format_arg}} stores a {{c|std::basic_format_arg<Context>::handle}} to {{tt|t}}, along with extra data needed for {{rlpt|basic_format_arg/handle|handle::format()}}. | ||
===Notes=== | ===Notes=== | ||
− | A formatting argument has reference semantics for user-defined types and does not extend the lifetime of {{ | + | A formatting argument has reference semantics for user-defined types and does not extend the lifetime of {{c|args}}. It is the programmer's responsibility to ensure that {{c|args}} outlive the return value. Usually, the result is only used as argument to formatting function. |
+ | |||
+ | {{ftm begin}} | ||
+ | {{ftm|__cpp_lib_format_uchar|Formatting of code units as unsigned integers|std=C++20|dr=yes|value=202311L}} | ||
+ | {{ftm end}} | ||
===Example=== | ===Example=== | ||
{{example | {{example | ||
− | + | |code= | |
#include <array> | #include <array> | ||
#include <format> | #include <format> | ||
Line 37: | Line 60: | ||
#include <string_view> | #include <string_view> | ||
− | void raw_write_to_log(std::string_view users_fmt, std::format_args&& args) { | + | void raw_write_to_log(std::string_view users_fmt, std::format_args&& args) |
+ | { | ||
static int n{}; | static int n{}; | ||
std::clog << std::format("{:04} : ", n++) << std::vformat(users_fmt, args) << '\n'; | std::clog << std::format("{:04} : ", n++) << std::vformat(users_fmt, args) << '\n'; | ||
} | } | ||
− | template <typename... Args> | + | template<typename... Args> |
− | constexpr void log(Args&&... args) | + | constexpr void log(Args&&... args) |
− | + | { | |
// Generate formatting string "{} "... | // Generate formatting string "{} "... | ||
std::array<char, sizeof...(Args) * 3 + 1> braces{}; | std::array<char, sizeof...(Args) * 3 + 1> braces{}; | ||
constexpr const char c[4] = "{} "; | constexpr const char c[4] = "{} "; | ||
− | for (auto i{ | + | for (auto i{0uz}; i != braces.size() - 1; ++i) |
braces[i] = c[i % 3]; | braces[i] = c[i % 3]; | ||
− | |||
braces.back() = '\0'; | braces.back() = '\0'; | ||
raw_write_to_log(std::string_view{braces.data()}, std::make_format_args(args...)); | raw_write_to_log(std::string_view{braces.data()}, std::make_format_args(args...)); | ||
+ | } | ||
+ | |||
+ | template<typename T> | ||
+ | const T& unmove(T&& x) | ||
+ | { | ||
+ | return x; | ||
} | } | ||
Line 59: | Line 88: | ||
{ | { | ||
log("Number", "of", "arguments", "is", "arbitrary."); | log("Number", "of", "arguments", "is", "arbitrary."); | ||
− | log("Any type that meets the | + | log("Any type that meets the BasicFormatter requirements", "can be printed."); |
log("For example:", 1, 2.0, '3', "*42*"); | log("For example:", 1, 2.0, '3', "*42*"); | ||
− | raw_write_to_log("{:02} │ {} │ {} │ {}", std::make_format_args(1, 2.0, '3', "4")); | + | raw_write_to_log("{:02} │ {} │ {} │ {}", |
+ | std::make_format_args(unmove(1), unmove(2.0), unmove('3'), "4")); | ||
} | } | ||
− | + | |output= | |
− | 0000 : Number of arguments is arbitrary. | + | 0000 : Number of arguments is arbitrary. |
− | 0001 : Any type that meets the | + | 0001 : Any type that meets the BasicFormatter requirements can be printed. |
− | 0002 : For example: 1 2.0 3 *42* | + | 0002 : For example: 1 2.0 3 *42* |
0003 : 01 │ 2.0 │ 3 │ 4 | 0003 : 01 │ 2.0 │ 3 │ 4 | ||
}} | }} | ||
+ | |||
+ | ===Defect reports=== | ||
+ | {{dr list begin}} | ||
+ | {{dr list item|paper=P2418R2|std=C++20|before=objects that are neither const-usable nor copyable<br>(such as generator-like objects) are not formattable|after=allow formatting these objects}} | ||
+ | {{dr list item|paper=P2905R2|std=C++20|before={{tt|make_format_args}} accepted rvalue arguments by forwarding references|after=only takes lvalue references}} | ||
+ | {{dr list item|paper=P2909R4|std=C++20|before={{c/core|char}} or {{c/core|wchar_t}} might be formatted as<br>out-of-range unsigned integer values|after=code units are converted to the corresponding<br>unsigned type before such formatting}} | ||
+ | {{dr list item|wg=lwg|dr=3631|std=c++20|before=cv-qualified arguments were incorrectly handled after P2418R2|after=handling corrected}} | ||
+ | {{dr list end}} | ||
===See also=== | ===See also=== | ||
{{dsc begin}} | {{dsc begin}} | ||
− | {{dsc inc | cpp/utility/format/dsc basic_format_args}} | + | {{dsc inc|cpp/utility/format/dsc basic_format_args}} |
+ | {{dsc inc|cpp/utility/format/dsc vformat}} | ||
+ | {{dsc inc|cpp/utility/format/dsc vformat_to}} | ||
{{dsc end}} | {{dsc end}} | ||
− | {{langlinks|ja|zh}} | + | {{langlinks|es|ja|ru|zh}} |
Latest revision as of 13:24, 26 February 2024
Defined in header <format>
|
||
template< class Context = std::format_context, class... Args > /*format-arg-store*/<Context, Args...> |
(1) | (since C++20) |
template< class... Args > /*format-arg-store*/<std::wformat_context, Args...> |
(2) | (since C++20) |
Returns an object that stores an array of formatting arguments and can be implicitly converted to std::basic_format_args<Context>.
The behavior is undefined if typename Context::template formatter_type<std::remove_const_t<Ti>> does not meet the BasicFormatter requirements for any Ti
in Args
.
The program is ill-formed if for any type Ti
in Args
, Ti
does not satisfy __formattable_with<Context>.
Contents |
[edit] Parameters
args... | - | values to be used as formatting arguments |
[edit] Returns
An object that holds the formatting arguments.
For each argument t
of type T
, let TD
be std::remove_const_t<std::remove_reference_t<T>>. The corresponding std::basic_format_arg in the result is determined as below:
- if
TD
is bool orContext::char_type
, the std::basic_format_arg stores t; - otherwise, if
TD
is char andContext::char_type
is wchar_t, the std::basic_format_arg stores static_cast<wchar_t>(static_cast<unsigned char>(t)); - otherwise, if
TD
is a signed integer type whose size is not greater than int, the std::basic_format_arg stores static_cast<int>(t); - otherwise, if
TD
is a unsigned integer type whose size is not greater than unsigned int, the std::basic_format_arg stores static_cast<unsigned int>(t); - otherwise, if
TD
is a signed integer type whose size is not greater than long long, the std::basic_format_arg stores static_cast<long long>(t); - otherwise, if
TD
is a unsigned integer type whose size is not greater than unsigned long long, the std::basic_format_arg stores static_cast<unsigned long long>(t); - otherwise, if
TD
is float, double, or long double, the std::basic_format_arg stores t; - otherwise, if
TD
is a std::basic_string_view or std::basic_string specialization andTD::char_type
isContext::char_type
, the std::basic_format_arg stores std::basic_string_view<Context::char_type>(t.data(), t.size()); - otherwise, if std::decay_t<TD> is Context::char_type* or const Context::char_type*, the std::basic_format_arg stores static_cast<const Context::char_type*>(t);
- otherwise, if std::is_void_v<std::remove_pointer_t<TD>> is true or std::is_null_pointer_v<TD> is true, the std::basic_format_arg stores static_cast<const void*>(t);
- otherwise, the std::basic_format_arg stores a std::basic_format_arg<Context>::handle to
t
, along with extra data needed forhandle::format()
.
[edit] Notes
A formatting argument has reference semantics for user-defined types and does not extend the lifetime of args. It is the programmer's responsibility to ensure that args outlive the return value. Usually, the result is only used as argument to formatting function.
Feature-test macro | Value | Std | Feature |
---|---|---|---|
__cpp_lib_format_uchar |
202311L | (C++20) (DR) |
Formatting of code units as unsigned integers |
[edit] Example
#include <array> #include <format> #include <iostream> #include <string_view> void raw_write_to_log(std::string_view users_fmt, std::format_args&& args) { static int n{}; std::clog << std::format("{:04} : ", n++) << std::vformat(users_fmt, args) << '\n'; } template<typename... Args> constexpr void log(Args&&... args) { // Generate formatting string "{} "... std::array<char, sizeof...(Args) * 3 + 1> braces{}; constexpr const char c[4] = "{} "; for (auto i{0uz}; i != braces.size() - 1; ++i) braces[i] = c[i % 3]; braces.back() = '\0'; raw_write_to_log(std::string_view{braces.data()}, std::make_format_args(args...)); } template<typename T> const T& unmove(T&& x) { return x; } int main() { log("Number", "of", "arguments", "is", "arbitrary."); log("Any type that meets the BasicFormatter requirements", "can be printed."); log("For example:", 1, 2.0, '3', "*42*"); raw_write_to_log("{:02} │ {} │ {} │ {}", std::make_format_args(unmove(1), unmove(2.0), unmove('3'), "4")); }
Output:
0000 : Number of arguments is arbitrary. 0001 : Any type that meets the BasicFormatter requirements can be printed. 0002 : For example: 1 2.0 3 *42* 0003 : 01 │ 2.0 │ 3 │ 4
[edit] Defect reports
The following behavior-changing defect reports were applied retroactively to previously published C++ standards.
DR | Applied to | Behavior as published | Correct behavior |
---|---|---|---|
P2418R2 | C++20 | objects that are neither const-usable nor copyable (such as generator-like objects) are not formattable |
allow formatting these objects |
P2905R2 | C++20 | make_format_args accepted rvalue arguments by forwarding references
|
only takes lvalue references |
P2909R4 | C++20 | char or wchar_t might be formatted as out-of-range unsigned integer values |
code units are converted to the corresponding unsigned type before such formatting |
LWG 3631 | C++20 | cv-qualified arguments were incorrectly handled after P2418R2 | handling corrected |
[edit] See also
(C++20)(C++20)(C++20) |
class that provides access to all formatting arguments (class template) |
(C++20) |
non-template variant of std::format using type-erased argument representation (function) |
(C++20) |
non-template variant of std::format_to using type-erased argument representation (function template) |