This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of WP status.
Section: 24.6.13 [container.adaptors.format] Status: WP Submitter: Victor Zverovich Opened: 2023-02-10 Last modified: 2023-02-13
Priority: Not Prioritized
View all issues with WP status.
Discussion:
According to 24.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'].
Here is an illustration of this issue on godbolt using {fmt} and an implementation of the formatter for container adapters based on the one from the standard: https://godbolt.org/z/P1nrM1986. A simple fix is to wrap the underlying container in std::views::all(_t) (https://godbolt.org/z/8MT1be838).Previous resolution [SUPERSEDED]:
This wording is relative to N4928.
Modify 24.6.13 [container.adaptors.format] as indicated:
-1- For each of queue, priority_queue, and stack, the library provides the following formatter specialization where adaptor-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 Status changed: Immediate → WP.]
Proposed resolution:
This wording is relative to N4928.
Modify 24.6.13 [container.adaptors.format] as indicated:
-1- For each of queue, priority_queue, and stack, the library provides the following formatter specialization where adaptor-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 26.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);