Date: Fri, 13 Dec 2024 13:26:57 +0000
On Fri, 13 Dec 2024 at 13:14, Robin Savonen Söderholm via Std-Proposals <
std-proposals_at_[hidden]> wrote:
> 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
>
What's magic about it?
> (which I'd refrain from just for the sake of potential
> ambiguous/conflicting specialisations),
>
Why is that any more likely for a variable template than for a class
template?
> 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.
>
Specializing a variable template is also explicit, and it's how we opt-in
or opt-out of various C++20 features, see enable_view,
enable_borrowed_range, disabled_sized_range. And it's also used in <format>
already, see enable_nonlocking_formatter_optimization and foramt_kind.
std-proposals_at_[hidden]> wrote:
> 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
>
What's magic about it?
> (which I'd refrain from just for the sake of potential
> ambiguous/conflicting specialisations),
>
Why is that any more likely for a variable template than for a class
template?
> 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.
>
Specializing a variable template is also explicit, and it's how we opt-in
or opt-out of various C++20 features, see enable_view,
enable_borrowed_range, disabled_sized_range. And it's also used in <format>
already, see enable_nonlocking_formatter_optimization and foramt_kind.
Received on 2024-12-13 13:28:14