C++ Logo

std-proposals

Advanced search

Re: [std-proposals] Format output-streamable types?

From: Robin Savonen Söderholm <robinsavonensoderholm_at_[hidden]>
Date: Fri, 13 Dec 2024 14:55:18 +0100
The specialisation of ` formatter_uses_ostream_insertion ` would be
explicit itself, but having:
```cpp
template <typename T>
requires(formatter_uses_ostream_insertion<T>)
struct formatter {...};
```
is not. I worry slightly that the formatter partial specialisation that
relies on ` formatter_uses_ostream_insertion` could spell trouble, more
specifically if we would be adding more variable-dependent specialisations
of a formatter. But maybe you propose that the variable is used in a
different way that I did not think of? Like when trying to instantiate the
regular formatter and failing, one could test that variable as well and
return a 'generic formatter that delegates to ostream'?

// Robin

On Fri, Dec 13, 2024 at 2:28 PM Jonathan Wakely <cxx_at_[hidden]> wrote:

>
>
> 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.
>

Received on 2024-12-13 13:55:43