> C may have limitations and deficiencies relative to modern programming concepts
That seems to be an understatement ;)
> Templates: These are a bodged implementation of generic/meta types
They're not. Stroustrup knew about ML (which had generics all along) when he designed C++, but he deliberately designed templates differently. ML-style generics require a boxed data representation and can't properly deal with stuff like overloaded assignment operators, and you can't specialize them. Templates and generics are two very different beasts, even though they serve similar purposes.
> Due to different instantiations of the same template literally copying the code, they're hell on I-caches - spectacularly inefficient.
They're not, actually. Try sorting a million floating point numbers with std::sort and qsort. The std::sort version will be much faster, because in a function template, the comparison can be inlined, while in the qsort version, you have to call it through a function pointer, defeating the CPU's branch prediction.
Also, partial template specialization can be (and is being) used to reduce or eliminate copied code. For example, it is possible to specialize the vector<T> class so that if T is a POD type (POD = plain old data), a generic implementation based on memcpy etc. will be used and the template merely acts as a type-safe wrapper around it, the overhead of which can be trivially optimized away by the compiler.
> Due to its implementation roots as code that's inserted in a pre-processor phase, producing compilation error messages that don't look like incomprehensible gobbledygook to anyone but C++ compiler developers and/or language spec committee members can be challenging.
Cfront never was any sort of preprocessor, it always was a proper compiler which just happened to generate C code as that was the only way to achieve good portability back then.
I agree that template error messages are a problem, but it's not an easy one to fix. The problem is that the compiler can't know if a failed template instantiation is due to a bug in the template or due to the type parameter not satisfying the requirements of the template.
In Haskell, type classes solve a similar problem fairly elegantly. They tried to add a similar feature to C++0x but failed, so this problem will be with us for some time.
> RAII: This is a programming pattern popularised, in large part, because of the *deficiencies* of C++, wrt the many subtle ways exceptions interact with other parts of the C++ language spec (construction and deconstruction particularly).
Every language needs to deal with some form of resource cleanup, and RAII is a very elegant way to do so. The fact that one motivation for RAII was exception safety doesn't change that in the least. What other solution for the resource cleanup problem do you propose? A GC doesn't count as it only deals with memory. I found the "finally" blocks found in many languages to be much less useful.
> Further, you *can* quite easily (if you're adhering to OOP) do RAII in C, as I'm sure you must know.
As I'm sure you must know, there is no such thing as an implicitly called destructor in C. This makes the idiom much less useful than it is in C++.
> So, again, if you got fed up with C and wanted to switch to a better language for some large, high-level user-space project (e.g. GUI graphics processing app), why on earth would you choose C++? Surely C#, Java, or Vala, perhaps others, would be a much better choice?
Hey, I didn't propose to rewrite the Gimp in C++, did I? Anyway, comparing C# etc. to C++ is a red herring. C++ is a systems programming language, and it was always meant to be. Which leads us to the next point...
> For the low-level, C beats C++.
I disagree. Everything you can do in C can also be done in C++, and it'll be cleaner and more elegant. In fact, I flat-out hate C. It needs to die a gory death, and the sooner that happens, the better. It just doesn't do what I need it to do, not even for low-level programming.