First off, you might want to read my 2009 article on this subject.
The primary difference to my mind between C++ templates and C# generics is that C++ templates actually completely recompile the code upon construction of the template. The pros and cons of the C++ approach are many:
PRO: You can effectively create constraints like "the type argument T must have an addition operator"; if the code contains a couple of Ts added to each other then the template will not compile if you construct it with a type argument that doesn't permit addition.
CON: You can accidentally create undocumented constraints like "the type argument T must have an addition operator".
In C# you have to say what the constraints are which helps the user, but you are limited to only a small set of possible constraints: interfaces, base classes, value vs reference type and default constructor constraints, and that's all.
PRO: Semantic analysis can be completely different for two different constructions. If you want that, that's awesome.
CON: Semantic analysis can be completely different for two different constructions. If you don't want that, that's a bug waiting to happen.
In C# the semantic analysis is done once no matter how many times the type is constructed, and it is therefore required to work with any type argument that meets the constraints, not just the type arguments that are actually supplied.
Templates can cause codegen to get large. In C#, the IL for a generic type is generated once, and then at runtime the jitter does codegen for all the types your program uses. This has a small performance cost, but it is mitigated somewhat by the fact that the jitter actually only generates code once for all reference type arguments. So if you have List<object>
and List<string>
then the jitted code is only generated once and used for both. List<int>
and List<short>
by contrast jits the code twice.
PRO: when you use a template library, you have the source code right there.
CON: to use a template library you have to have the source code.
In C#, generic types are first-class types. If you stick them in a library, you can use that library anywhere without having to ship the source code.
And finally:
PRO: Templates permit template metaprogramming.
CON: Template metaprogramming is hard to understand for novices.
CON: The template system actually does not permit some type topologies that are extremely straightforward in a generic system.
For example, I imagine that it would be difficult to do something like this in C++:
class D<T>
{
class S { }
D<D<T>.S> ds;
}
In C# generics, no problem. At runtime the type is only built once for all reference type arguments.
But in C++ templates, what happens when you have D<int>
? The interior type constructs a field of type D<D<int>.S>
, so we need to construct that type. But that type constructs a field of type D<D<D<int>.S>.S>
... and so on to infinity.