Strings in C++ are nice, especially now that we have std::string_view, but <iostream> is one of the worst pieces of the C++ standard library.
- <iostream> makes localization more difficult, compared to printf (localizing <iostream> code is beyond awful)
- <iostream> makes thread safety more difficult, compared to printf (it is safe to printf/fprintf from multiple threads, simultaneously, without any extra work)
- The <iostream> operator overloading syntax is bad (my sense is that the operator overloading abuse in <iostream> was a contributing factor for why Java doesn't allow operator overloading)
- Streams in <iostream> are stateful, and it's easy to accidentally leave them in the wrong state (radix, padding, field width, etc)
- Performance of <iostream>, out of the box, is mediocre (to get decent performance, you need to change some defaults)
The main advantage of <iostream> was that it provided type safety, but IMO that advantage has long since been irrelevant. You get type safety with std::printf, with most compilers, assuming you enable -Wformat on GCC or similar options in other compilers.
The only remaining advantage of <iostream> is that you can overload operator<<. I don't think that's much of an advantage, especially weighed against the numerous disadvantages.
Using std::printf is better and more portable. Libfmt is also better and more portable, and it is now part of the standard library as std::format.
https://www.moria.us/articles/iostream-is-hopelessly-broken/