This fails when you want `4 + c` or `c + 4.f` etc. So you either have a gross number of overloads doing the same thing, or you just put an implicit constructor to `complex`.
Also, I agree that implicit conversions in general should be avoided, but this complex number example feels like the perfect use case.
Would you rather have this line not compile because 4 is not a complex number? Because one _could_ argue that 4 is a complex number, and C++ can represent this with an implicit constructor.
The issue with C++ is that implicit is the default, not that it exists.
If your data type implements the Num typeclass, you can use literals like 4. (A typeclass in Haskell is similar to what they call an interface in Java.)
There's no automatic conversion happening at all. It's done via overloading literals at compile time. (You can do the same for strings.)
C++20 introduced concepts, and now it's possible to specify type constraints, like integral, in a way similar to Haskell typeclasses.
What it doesn't solve that by default the compiler tries to find an appropriate implicit conversion. Sometimes it's convenient, sometimes it's harder to see what the code actually does.
Also, I agree that implicit conversions in general should be avoided, but this complex number example feels like the perfect use case.