Finally, a guru dares to call a spade a spade. Header-only, template-only C++ programming is a mistake! After 1995 C++ Standardization took the wrong path and lost contact with real world developers. The glorification and idolization of 'STL programming' was in sharp contrast with programmer's needs. Today in C++ there is a chasm like in no other language between the 'official language' and what programmers need and use day in day out.
And now a whole new generation of programmers can gaze at the horror of Modern C++ metaprogramming and conclude that metaprogramming is bad....
If you'd asked the standards body to add a turing complete type-level meta-programming language to C++ in order to generate code at compile time I suspect they'd have told you to get knotted.
What people actually asked for was a reasonable syntax for adding generic functions to C++ that would not carry any runtime cost. Sounds completely reasonable, right? The standards group said "sure, how about this?", and kept adding more perfectly reasonable individual requests to the syntax like template specialisation. Only afterwards did the true nature of crawling horror that they'd inadvertently unleashed become apparent.
Remember the STL is complicated because it tries to be super generic, and it tries to be super generic because it's a library so it tries to cater for all possible uses. If you're writing a program instead of a library, you can make things orders of magnitude simpler because you only have to provide what you need, not everything any programmer on Earth might need.
Java Swing using anonymous classes to 10 or more depths to represent callbacks because OOP and inheritance > all.
Haskell having one file IO operation a thousand feet below the surface of a program "un-purifying" the entire call stack with side effects because pure functional is king.
Trying to implement any generic anything in C, because in procedural having template or inheritance based polymorphic behavior is crazy, so you end up with 5 million ways to write readNumber() for every numeric type ever.
So go figure, procedural, meta, functional and OOP all go completely deep end when you try to kitchen sink them as the be all end all solution to all problems and woes.
And that's the way it should be. (Refator your programme, if you want to keep the other functions pure. But it is a Good Thing (TM), that you can not hide your IO if you pile on enough layers.) Haskell has other problems, though.