Date: Fri, 13 Dec 2024 14:56:20 +0100
Opps, slight error in last post. Code snippet should of course be:
```cpp
template <typename T> // partial specialisation that depends on variable.
requires(formatter_uses_ostream_insertion<T>)
struct formatter<T> {...};
```
// Robin
On Fri, Dec 13, 2024 at 2:55 PM Robin Savonen Söderholm <
robinsavonensoderholm_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 {...};
> ```
> 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.
>>
>
```cpp
template <typename T> // partial specialisation that depends on variable.
requires(formatter_uses_ostream_insertion<T>)
struct formatter<T> {...};
```
// Robin
On Fri, Dec 13, 2024 at 2:55 PM Robin Savonen Söderholm <
robinsavonensoderholm_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 {...};
> ```
> 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:56:45