Date: Sat, 14 Dec 2024 13:21:48 +0100
How is `print_to_sink` different from
`format_to(ostreambuf_iterator<char>(cout), <format string>,
...<arguments>)`? More than verbosity of course..
I hacked together some implementations here: (godbolt):
https://godbolt.org/z/G44dEabjq and (github): doocman/dtl: Doocman
Template Library (C++) <https://github.com/doocman/dtl> .
There are probably details about these that could be improved, but my hope
is that the overall behaviour is fine, but I'll gladly take some feedback
while trying to write out a proper proposal.
// Robin
On Fri, Dec 13, 2024 at 10:05 PM Tiago Freire <tmiguelf_at_[hidden]> wrote:
> The lazy_format, although not entirely a bad idea what you gain from it is
> mostly peanuts.
>
> Because of the way the operator << mechanism works the implementation has
> to resolve each of the segments (i.e. << “segment one” << “segment two” <<
> etc..) one by one and cannot optimize with the fact that there are more
> segments following, this despite the fact that all segments will be
> available in the stack before the last “<<” in the chain completes.
>
> A much more efficient way to handle this is to completely forgo the usage
> of any ostream operator and just pass the ostream object as one of the
> arguments, like so:
>
> print_to_sink(std::cout, "formatting string", …arguments); //pass
> arguments as a reference is better.
>
>
>
> Which can be made more generic as:
>
> print_to_sink<underlying_encoding>(<generic_sink>, <format string>,
> …<arguments>);
>
>
>
> This allows for the function to introspect about all arguments and be much
> more efficient (and I’m talking easily a couple of orders of magnitude
> faster, not just a mere 10%).
>
>
>
> Take it for what it is, it is an opinion, my opinion is that std::ostream
> is obsolete and should eventually be deprecated and removed, it’s a waste
> of time to try and upgrade it.
>
>
>
>
>
>
>
> *From:* Std-Proposals <std-proposals-bounces_at_[hidden]> *On Behalf
> Of *Robin Savonen Söderholm via Std-Proposals
> *Sent:* Friday, December 13, 2024 2:14 PM
> *To:* std-proposals_at_[hidden]
> *Cc:* Robin Savonen Söderholm <robinsavonensoderholm_at_[hidden]>
> *Subject:* Re: [std-proposals] Format output-streamable types?
>
>
>
> Ok, taking feedback from you both I propose this:
>
> - Add even more specialisations to std::formatter (one paper)
>
> - Look at a way to let users delegate the format (output stream) to the
> output stream (formatter).
> The first one feels somewhat trivial, and I do think that the standard
> should have a formatter specialisation for all types that already provide
> an operator << to an ostream.
> The second one may need some design, I'll try to work it out during the
> weekend. At the top of my head I was thinking about something like this:
> To format <<:
> ```c++
> std::print("foo only provides operator<< but here I print it anyway: {}",
> stream_formatter(foo));
> ```
> The other one I think could be nicely solved by another construct that I
> have been wanting to implement: lazy_formatted_string and lazy_format, so
> that we could write something like this:
> ```c++
> std::cout << "bar only supports the modern formatting facilities but here
> I let a lazy_formatted_string to efficiently stream to cout without
> intermediate allocations " << lazy_format("{}", bar);
> ```.
> My main concern with these API:s are wheter they should capture by value,
> by reference or some automatic version of either (value for trivial types
> and for r-value inputs, reference for non-trivial lvalue inputs for
> example). I also like the idea of the lazy_format to allow some
> optimisations in the std::string::operator= department:
> ```cpp
> std::string str = ...;
> // and some while later:
> // same as str.clear(); std::format_to(std::backinserter(str), "...", ...);
> str = lazy_format("....", ...);
> ```
> but these lazy-evaluation stuff may lead to life-time issues for careless
> users (although we already have the same issue with std::span and
> std::string_view).
>
> Anyway, if no objections are made I'll look into some implementations
> later and hopefully come back with a more fleshed-out proposal. Thanks!
>
> PS: rather than having the magic ` formatter_uses_ostream_insertion
> `-variable (which I'd refrain from just for the sake of potential
> ambiguous/conflicting specialisations), I think it would make more sense to
> have a template-base class that you may use for your formatter:
>
> ```cpp
> namespace std {
> template <typename Char>
> struct formatter<my_namespace::foo, Char> :
> ostream_formatter<my_namespace::foo, Char> {};
> }
> ```
> .
> I prefer it because it feels slightly more explicit.
> DS.
>
> // Robin
>
>
>
> On Thu, Dec 12, 2024, 22:21 Jonathan Wakely <cxx_at_[hidden]> wrote:
>
>
>
>
>
> On Thu, 12 Dec 2024 at 20:24, Robin Savonen Söderholm via Std-Proposals <
> std-proposals_at_[hidden]> wrote:
>
> Ok, so just a proposal to add more formatter specialisations?
>
>
>
> See https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1636r2.pdf
>
>
>
> Formatters for thread::id and filesystem::path have now been added, the
> rest haven't.
>
>
>
>
>
> Users wanting "auto conversions" would have to implement them themselves.
>
>
>
> I like the idea of some kind of reuse between operator<< and
> std::formatter, maybe opt-in. I see no reason why we would ever want to
> completely remove basic_ostream.
>
>
>
> We could have a variable template like:
>
>
>
> template<typename T>
>
> constexpr bool formatter_uses_ostream_insertion = false;
>
>
>
> and then define a formatter specialization that only supports empty format
> specs and uses operator<< to produce a string/wstring:
>
>
>
> template<typename T>
>
> requires formatter_uses_ostream_insertion<T>
>
> class formatter<T> // ...
>
>
>
> We could also provide the reverse opt-in, so that ostream insertion uses
> std::format (or std::format_to) to write to the ostream.
>
>
>
> And we could provide a generic std::to_string(T) function which uses
> std::format if the type is formattable, and operator<< if that works (and
> is ill-formed otherwise).
>
>
>
> There's lots of room for improvement in this space.
>
>
>
>
>
>
`format_to(ostreambuf_iterator<char>(cout), <format string>,
...<arguments>)`? More than verbosity of course..
I hacked together some implementations here: (godbolt):
https://godbolt.org/z/G44dEabjq and (github): doocman/dtl: Doocman
Template Library (C++) <https://github.com/doocman/dtl> .
There are probably details about these that could be improved, but my hope
is that the overall behaviour is fine, but I'll gladly take some feedback
while trying to write out a proper proposal.
// Robin
On Fri, Dec 13, 2024 at 10:05 PM Tiago Freire <tmiguelf_at_[hidden]> wrote:
> The lazy_format, although not entirely a bad idea what you gain from it is
> mostly peanuts.
>
> Because of the way the operator << mechanism works the implementation has
> to resolve each of the segments (i.e. << “segment one” << “segment two” <<
> etc..) one by one and cannot optimize with the fact that there are more
> segments following, this despite the fact that all segments will be
> available in the stack before the last “<<” in the chain completes.
>
> A much more efficient way to handle this is to completely forgo the usage
> of any ostream operator and just pass the ostream object as one of the
> arguments, like so:
>
> print_to_sink(std::cout, "formatting string", …arguments); //pass
> arguments as a reference is better.
>
>
>
> Which can be made more generic as:
>
> print_to_sink<underlying_encoding>(<generic_sink>, <format string>,
> …<arguments>);
>
>
>
> This allows for the function to introspect about all arguments and be much
> more efficient (and I’m talking easily a couple of orders of magnitude
> faster, not just a mere 10%).
>
>
>
> Take it for what it is, it is an opinion, my opinion is that std::ostream
> is obsolete and should eventually be deprecated and removed, it’s a waste
> of time to try and upgrade it.
>
>
>
>
>
>
>
> *From:* Std-Proposals <std-proposals-bounces_at_[hidden]> *On Behalf
> Of *Robin Savonen Söderholm via Std-Proposals
> *Sent:* Friday, December 13, 2024 2:14 PM
> *To:* std-proposals_at_[hidden]
> *Cc:* Robin Savonen Söderholm <robinsavonensoderholm_at_[hidden]>
> *Subject:* Re: [std-proposals] Format output-streamable types?
>
>
>
> Ok, taking feedback from you both I propose this:
>
> - Add even more specialisations to std::formatter (one paper)
>
> - Look at a way to let users delegate the format (output stream) to the
> output stream (formatter).
> The first one feels somewhat trivial, and I do think that the standard
> should have a formatter specialisation for all types that already provide
> an operator << to an ostream.
> The second one may need some design, I'll try to work it out during the
> weekend. At the top of my head I was thinking about something like this:
> To format <<:
> ```c++
> std::print("foo only provides operator<< but here I print it anyway: {}",
> stream_formatter(foo));
> ```
> The other one I think could be nicely solved by another construct that I
> have been wanting to implement: lazy_formatted_string and lazy_format, so
> that we could write something like this:
> ```c++
> std::cout << "bar only supports the modern formatting facilities but here
> I let a lazy_formatted_string to efficiently stream to cout without
> intermediate allocations " << lazy_format("{}", bar);
> ```.
> My main concern with these API:s are wheter they should capture by value,
> by reference or some automatic version of either (value for trivial types
> and for r-value inputs, reference for non-trivial lvalue inputs for
> example). I also like the idea of the lazy_format to allow some
> optimisations in the std::string::operator= department:
> ```cpp
> std::string str = ...;
> // and some while later:
> // same as str.clear(); std::format_to(std::backinserter(str), "...", ...);
> str = lazy_format("....", ...);
> ```
> but these lazy-evaluation stuff may lead to life-time issues for careless
> users (although we already have the same issue with std::span and
> std::string_view).
>
> Anyway, if no objections are made I'll look into some implementations
> later and hopefully come back with a more fleshed-out proposal. Thanks!
>
> PS: rather than having the magic ` formatter_uses_ostream_insertion
> `-variable (which I'd refrain from just for the sake of potential
> ambiguous/conflicting specialisations), I think it would make more sense to
> have a template-base class that you may use for your formatter:
>
> ```cpp
> namespace std {
> template <typename Char>
> struct formatter<my_namespace::foo, Char> :
> ostream_formatter<my_namespace::foo, Char> {};
> }
> ```
> .
> I prefer it because it feels slightly more explicit.
> DS.
>
> // Robin
>
>
>
> On Thu, Dec 12, 2024, 22:21 Jonathan Wakely <cxx_at_[hidden]> wrote:
>
>
>
>
>
> On Thu, 12 Dec 2024 at 20:24, Robin Savonen Söderholm via Std-Proposals <
> std-proposals_at_[hidden]> wrote:
>
> Ok, so just a proposal to add more formatter specialisations?
>
>
>
> See https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1636r2.pdf
>
>
>
> Formatters for thread::id and filesystem::path have now been added, the
> rest haven't.
>
>
>
>
>
> Users wanting "auto conversions" would have to implement them themselves.
>
>
>
> I like the idea of some kind of reuse between operator<< and
> std::formatter, maybe opt-in. I see no reason why we would ever want to
> completely remove basic_ostream.
>
>
>
> We could have a variable template like:
>
>
>
> template<typename T>
>
> constexpr bool formatter_uses_ostream_insertion = false;
>
>
>
> and then define a formatter specialization that only supports empty format
> specs and uses operator<< to produce a string/wstring:
>
>
>
> template<typename T>
>
> requires formatter_uses_ostream_insertion<T>
>
> class formatter<T> // ...
>
>
>
> We could also provide the reverse opt-in, so that ostream insertion uses
> std::format (or std::format_to) to write to the ostream.
>
>
>
> And we could provide a generic std::to_string(T) function which uses
> std::format if the type is formattable, and operator<< if that works (and
> is ill-formed otherwise).
>
>
>
> There's lots of room for improvement in this space.
>
>
>
>
>
>
Received on 2024-12-14 12:22:01