On Fri, 13 Dec 2024 at 13:14, Robin Savonen Söderholm via Std-Proposals <std-proposals@lists.isocpp.org> 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.