std::string
Section: 23.6.13 [container.adaptors.format] Status: C++23 Submitter: Victor Zverovich Opened: 2023-02-10 Last modified: 2023-11-22
Priority: Not Prioritized
View all issues with C++23 status.
Discussion:
According to 23.6.13 [container.adaptors.format] container adapters such as std::stack
are
formatted by forwarding to the underlying container:
template<class FormatContext> typename FormatContext::iterator format(maybe-const-adaptor& r, FormatContext& ctx) const;Effects: Equivalent to:
return underlying_.format(r.c, ctx);
This gives expected results for std::stack<T>
and most types of underlying container:
auto s = std::format("{}", std::stack(std::deque{'a', 'b', 'c'})); // s == "['a', 'b', 'c']"
However, when the underlying container is std::string
the output is:
auto s = std::format("{}", std::stack{std::string{"abc"}}); // s == "abc"
This is clearly incorrect because std::stack
itself is not a string (it is only backed by a string)
and inconsistent with formatting of ranges where non-string range types are formatted as comma-separated values
delimited by '['
and ']'
. The correct output in this case would be ['a', 'b', 'c']
.
std::views::all(_t)
(https://godbolt.org/z/8MT1be838).
Previous resolution [SUPERSEDED]:
This wording is relative to N4928.
Modify 23.6.13 [container.adaptors.format] as indicated:
-1- For each of
queue
,priority_queue
, andstack
, the library provides the following formatter specialization whereadaptor-type
is the name of the template:[…]namespace std { template<class charT, class T, formattable<charT> Container, class... U> struct formatter<adaptor-type<T, Container, U...>, charT> { private: using maybe-const-adaptor = // exposition only fmt-maybe-const<adaptor-type<T, Container, U...>, charT>; formatter<views::all_t<const Container&>, charT> underlying_; // exposition only public: template<class ParseContext> constexpr typename ParseContext::iterator parse(ParseContext& ctx); template<class FormatContext> typename FormatContext::iterator format(maybe-const-adaptor& r, FormatContext& ctx) const; }; }template<class FormatContext> typename FormatContext::iterator format(maybe-const-adaptor& r, FormatContext& ctx) const;-3- Effects: Equivalent to:
return underlying_.format(views::all(r.c), ctx);
[2023-02-10 Tim provides updated wording]
The container elements may not be const-formattable so we cannot
use the const
formatter unconditionally. Also the current wording
is broken because an adaptor is not range and we cannot use
fmt-maybe-const
on the adaptor — only the underlying container.
[Issaquah 2023-02-10; LWG issue processing]
Move to Immediate for C++23
[2023-02-13 Approved at February 2023 meeting in Issaquah. Status changed: Immediate → WP.]
Proposed resolution:
This wording is relative to N4928.
Modify 23.6.13 [container.adaptors.format] as indicated:
-1- For each of
queue
,priority_queue
, andstack
, the library provides the following formatter specialization whereadaptor-type
is the name of the template:[…]namespace std { template<class charT, class T, formattable<charT> Container, class... U> struct formatter<adaptor-type<T, Container, U...>, charT> { private: using maybe-const-container = // exposition only fmt-maybe-const<Container, charT>; using maybe-const-adaptor = // exposition onlyfmt-maybe-const<is_const_v<maybe-const-container>, adaptor-type<T, Container, U...>, charT>; // see 25.2 [ranges.syn] formatter<ranges::ref_view<maybe-const-container>Container, charT> underlying_; // exposition only public: template<class ParseContext> constexpr typename ParseContext::iterator parse(ParseContext& ctx); template<class FormatContext> typename FormatContext::iterator format(maybe-const-adaptor& r, FormatContext& ctx) const; }; }template<class FormatContext> typename FormatContext::iterator format(maybe-const-adaptor& r, FormatContext& ctx) const;-3- Effects: Equivalent to:
return underlying_.format(r.c, ctx);