I wrote a C++ compiler back in 2000. It took me couple of years to polish that. And it was not even the full compiler: parser and semantic analysis, but no code generation in the usual sense. It did, however, support several idiosyncratic compiler dialects.
C++ is an ugly, ugly, _ugly_ language. Even C language, the base of C++, is context-dependent, which in practice means that you need to intermix parsing and semantic analysis. Consider for example this code 'T*t'. If 'T' is a type, then this is declaration of variable 't' that is pointer to 'T'. If it is identifier, then it is non-assigned multiplication of 'T' and 't'.
C++ added its own quirks on top of that. You have, for example, parse class definitions two times. First, just the declarations and only then inline method bodies. There is no other way to do it correctly.
While I'm no fan of C++, I find it odd that people criticize languages as "ugly" because they are difficult to build correct parsers, compilers, etc. for. While obviously this is annoyance to the tool writer, I would think it is more important how useful (and clarity and expressiveness are important here) the language is to people who have to read and write code in the language, rather than how easy it is to write tooling that parses or compiles the language.
Seems to me that calling a language ugly on the basis of how it is to build a compiler is like calling a dish ugly because it takes skill to prepare it properly.
(That said, I think C++ is an ugly language, but not for the reasons stated in your post.)
C++ is an ugly, ugly, _ugly_ language. Even C language, the base of C++, is context-dependent, which in practice means that you need to intermix parsing and semantic analysis. Consider for example this code 'T*t'. If 'T' is a type, then this is declaration of variable 't' that is pointer to 'T'. If it is identifier, then it is non-assigned multiplication of 'T' and 't'.
C++ added its own quirks on top of that. You have, for example, parse class definitions two times. First, just the declarations and only then inline method bodies. There is no other way to do it correctly.
And don't even get me started on semantics.