Weaknesses Of C++
Because the lack of different in brackets and parentheses on a regular keyboard, the syntax of modern C++ sometimes gets complex. And not only for people, but for code highlighting too, which should tell us something.
Let’s see:

<>: Template declaration and usage. And bitwise shift operators if used as << and >>, also overloaded as reads and writes into streams.This is for shifting on either left or right side. Before few years, back  these two use cases were being regularly confused by various compilers, and programmers had to receive extra spaces in complex templates.

[] : Array indexing. And lambda definition / capture list. Oh, and also Objective-C uses square brackets to send messages.

{} : Code blocks. Only code blocks, right? Wrong. Also initialization. And the modern idealize makes a heavy push towards {}-based initialization.

(): Construction of variables, definition/declarations of functions, function calls. The first two cases can be disoriented in a remarkable fashion, and the “issue” still exists.  prepare for macros too. Ah, and casts (h/t Nathan F Yospe).

/* */ : Comments. Unambiguous, right? Wrong. At times “/*” can be a legal language construct extend the comment: int* pa = &a; int* pb = &b; int c = *pa / *pb, and we suddenly have a place where C++ requires a whitespace among among operators.

#if / #endif

On the one hand, I’m happy C++ folks are creating heavy use of existing semantics and are not accessing to reinvent the wheel. Haskell, Ruby, and F#, where the range of capability adding new operators is broadly used, often scare me by their syntax. C++ won’t be C++ if it starts using some “@”, “=>”, “$”, or “<* … *>” + “(* … *)” constructs.
On the other hand, if only we could use various pairs of brackets/parentheses for program code and data initialization, for lambdas and array indexing, for function definitions and calls, and for macros, the language would read so much clear to my taste. Too bad our keyboards and the ASCII table don’t proposal viable options.