C++ Logo

std-proposals

Advanced search

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

From: Jonathan Wakely <cxx_at_[hidden]>
Date: Fri, 13 Dec 2024 14:37:15 +0000
On Fri, 13 Dec 2024 at 13:55, Robin Savonen Söderholm via Std-Proposals <
std-proposals_at_[hidden]> wrote:

> 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 {...};
> ```
>

Ah I see what you mean. Not ambiguities in the variable template, but
between the formatter partial specialization above and _some other formater
specialization_ coming from somewhere else (possibly a future version of
the standard library).

Yes, that could be a problem. Although for another specialization coming
from the standard library, it would be up to the standard library to ensure
the specializations are disjoint (either by using subsumption or explicitly
checking both variables). For user specializations, it would be user error
to specialize the variable template *and* provide your own specialization
(although most of the time the latter would be more specialized and so
would be unambiguous).



> 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.
>>
> --
> Std-Proposals mailing list
> Std-Proposals_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
>

Received on 2024-12-13 14:38:36