Most of those benefits apply to std::format which was already introduced in c++20. But formatting a string you will often want to output it somewhere. You could do `std::cerr << std::format(....)`, but that just invites weird mixes of std::format and iostream based formatting. I look at print/println as partially just convenience function combing the existing std::format functionality with outputing to something. Not sure if standard permits it but print could also allow skipping some temporary heap allocated std::string which the std::format returns by directly writing to the output stream buffer.

In C++20 if you wanted to print using std::format style formating (or it's variant) your options where:

```

std::cout << std::format("{}{}", arg1, arg2);// not the best syntax but less bad than everything else, slightly inefficient due to temp string

std::string tmp = std::format("{} {}", arg1, arg2);
fwrite(stdout, tmp.c_str(), tmp.length()); // more ugly, and still uses temporary string

std::format_to(std::ostream_iterator<char>(std::cout), "{} {}", arg1, arg2); // avoids temp string, but what kind of monstrosity is this

```

But doesn't the std::format style formatting make the formatting part of ostream redundant -> it somewhat does. I guess that's why there are 3 types of print overloads:

* accepting ostream as first argument

* accepting c style "FILE*" as first output argument

* no output stream argument, implicitly outputting to stdout

One potential consideration to use ostream based versions instead of FILE* ones even though the formatting part is somewhat redundant, is RAII based resource management. If you want to use FILE* based versions, it means that you have to either remember manually close the File* handle which just like manual new/delete or malloc/free calls is something modern C++ tries to move away, or you have to create your own RAII wrappers around c style FILE* handles.

An alternative would have been introducing new kind of output stream API which only concerns with outputing buffered stream of bytes and skips the formatting part of ostream, but that would have introduced different kind of redundancy -> having 3 kinds of API for opening and writing to file. Allowing to pass ostream to print, while discouraging use of << operator parts of it seems like a simpler solution.

One more concern is how using the version of print which outputs to stdout without taking output File or ostream handle interacts with any buffering done by previous printf,and std::cout APIs and also synchronization with input streams. The same problem already existed before for interactions between printf and std::cout. For the most part if you don't mix them it doesn't matter too much, but if you care the standard defines how exactly they are synchronized. The new print probably either adds third case to this or is defined as being equivalent to one of the previous two.

After looking reading docs a bit more, seems like std::basic_streambuf/std::file_buf did exist. The new print API, might have used that as abstraction around output streams without some of the ostream formatting baggage. I have only seen them mentioned as implementation details of ostream stuff, never seen anyone use them directly.

There was also std::format_to in c++20 which avoid the temporary string std::format returns. I guess they could have extended that with additional overloads so that it can function more similar to std::print. But if they need to define new functions might as well call them something more familar to people coming from other languages like print, instead of having format_to(stdout, "formatstring", arg1, arg2);. Currently std::format_to outputs to output iterator.

So to sumarize why print exists:
- combine std::format introduced by C++20 with outputting somewhere with cleaner syntax compared to doing it manually.

- sane looking hello world for beginner and people coming from other programming languages, this is probably also why println exists

- (maybe) avoid some heap allocations that temporary string returned by std::format would cause.

- avoid confusion of mixing two formatting approaches that `std::cout<<std::format()` implies

- avoid C style manual resource management that would be required for doing `File\* f=fopen("");auto tmp=std::format();write(f, tmp.c_str())`