C++ is the reason people have that reaction. The quintessential example in introductory texts for operator overloading is using bit-shift operators to output text. I mean, come on - if that’s your example, don’t complain when people follow suit and get it wrong.
C++ has std::format these days that does a far more sane thing, people are too quick to throw out the baby with the bathwater when it comes to bad things.
Some OO is fine, just don't make your architecture or language entirely dependent on it. Same with operator overloading.
When it comes to math heavy workloads, you really want a language that supports operator overloading (or have a language full of heavy vector primitives), doing it all without just becomes painful for other reasons.
Yes, the early C++ _STDLIB_ was shit early on due to boneheaded architectural and syntactic decisions (and memory safety issues is another whole chapter), but that doesn't take away that the language is a damn powerful and useful one.
std::format in C++20 is just for the string manipulation half but you still left shift cout by the resulting string to output text in canonical C++.
C++23 introduced std::print(), which is more or less the modernized printf() C++ probably should have started with and also includes the functionality of std::format(). Unfortunately, it'll be another 10 years before I can actually use it outside of home projects... but at least it's there now!
While that operator is also used for bit-shift, it is not the bit-shift operator. It's not that the bit-shift operator is used for stream direction, it's that the same operator is used for both stream direction and bit-shifts. And which code is operating on both high-level abstract streams and bit-shifts at the same time.