Some people that are complaining about C++ templates (and suggesting generics from other languages as alternatives) are missing the code generation aspect of templates.
Generics operate entirely at the Type level. For instance (using java)
List<Integer> list = new ArrayList<Integer>();
list.add(1);
Integer i = list.get(0);
is under the hood equivalent to
List<Object> list = new ArrayList<Object>();
list.add(new Integer(1));
Integer i = (Integer)list.get(0);
The differences between the two snippets are entirely at the type level - they compile to the exact same bytecode. Templates are strictly more powerful - they allow you to generate different code for each instantiation. The most obvious place where this is useful is when dealing with primitives that take up different sizes in memory. This is why you can't use generics in Java with primitives - you need Objects, because pointers to objects are always the same size. But if you want performance, so you want to be able to represent collections of primitives generically, then you need the power of templates because you need your code to compile to different things depending on the template parameters.
In their basic form templates solve an obvious problem in an obvious way. It doesn't make sense to make the same data structure for every type, you want to make the data structure generic and sub in the type every time you use it.
The extremes of template meta programming are self imposed by people being fancy while writing libraries and the value is questionable. On top of that no one thinks that C++ templates are the ideal way to do complex meta programming.
For what it's worth, unless you're writing a library, you probably shouldn't be writing your own template code. Most uses of templates I see are unjustified complexity.
That said, template generics are pretty damn awesome in terms of performance/behavior guarantees
Templates can do a lot more than generics can, but come with corresponding downsides.
Templates are basically a form of copy/paste style substitution with fancy bits. When you instantiate std::vector<char> in C++, the compiler creates an entirely new class with "char" substituted in everywhere the type variable appears. This class has nothing in common with std::vector<MyStruct> - there's no common superclass, the compiled code may or may not be shared depending on low level details of your toolchain and the types involved, etc. That in turn means if you want to write a function that works for any std::vector you must also use templates, and your function will also be substituted, and your final binary will also have many similar-but-different copies of the compiled code, etc. However because of how C++ templates work you can achieve some pretty astonishing things with them. In particular you're getting code compiled and tuned to the exact data type it was instantiated with, so you can go pretty fast with certain data layouts.
Java generics seem superficially similar but in fact are different. In (erased) generics, a List<Foo> and List<Bar> are exactly the same class at runtime. They're both just List and both just contain objects. The compiled code is the same, you can cast between them if you know what you're doing, etc. Likewise if you write a generic function that works for any list, there's only one copy of that function. Generics have different tradeoffs: they're less powerful (you can't write a regex library with them for instance), and they don't auto-tune themselves to particular data types ... at least not until Project Valhalla comes along ... but they're backwards compatible with pre-generic libraries at a binary level and they avoid an explosion of compiled code bloat, which is a common problem with templates.
Besides C++ templates are a result of creating a conceptually simple, one size fits all solution for generics, metaprograming, library tuning, and some dozens of other problems that other languages have specialized tools to solve. Turns out that the complex set of features works better.
Templates don't exist until compile time, until you build the code, the IDE plugin doesn't have the full data on what types exactly are there. Java/C# generics are more limited in functionality, but it's a tradeoff in exchange for better ahead of time knowledge of types.
Templates expand, and can generate arbitrary amounts of code. If you, as a developer, don't see what happens, then you might miss it.
Templates can also expand on each type they use, or combination of types, generating much more code, when non-template solutions could have avoided it. Of course, templates could avoid it too, but they're much harder to write and see how they expand.
That said, templates also allow making code shorter and cleaner.
So some people, once bitten by bad templates or bad usage, complain without learning how to use them. Yet another C++ ocean of complexity :)
Oh, come now, calling C++ templates generics belittles their power. :p Honestly, the one thing I miss in any language is the complete power of C++ templates, but I definitely understand others' reluctance to include something like them in their language. Something that allows me to write simple generic functionality a la Java generics and not have to write the same code multiple times is good enough for me in go.
Luckily I do have some ability to use C++ at my current job, so I can get my fix again there :)
I wouldn't compare it like that. Templates are more like meta-programming. Templates can achieve what you can do with Java generics, but they can also do a lot more.
I think the point is that templates themselves can't contain logic. All logic is declared at compile time so that the compiler can optimize it, but then used at runtime like any other templating language.
The issue with templates is that you can’t really type check them at the point of definition. Instead they need to be checked each time the template is used.
This can make compilation slow but it can also make template writing very hard because a bug might only appear when a template is instantiated with certain types.
Ok this is seriously amazing (coming from a C++ guy). However, one thing I don't like with putting matrix dimensions in templates is that then you can't construct them at runtime. I do understand the obvious - that you can't have both static type checks on all operations and runtime-determined matrix sizes. Though I would kill for a language which would specialise my code at runtime and throw an exception for compilation errors. So you could write, e.g.
template <int m, int n, int l>
Matrix<m, l>
mul(Matrix<m, n> lhs, Matrix <n, l> rhs)
{...impl...}
And then be able to call it like
int m, n, k, l = ... read from file or whatever
Matrix <m, n> m1 = ...;
Matrix <k, l> m2 = ...;
try {
Matrix <int o, int p> m3 = m1 * m2;
// ^ code compiled dynamically
// or loaded from cache, based on
// runtime types of m1 and m2.
// o and p set to the result
// of type inference.
// I could imagine even having
// specialised versions with inline
// assembly for specific dimensions.
} catch (DynamicCompilationException e) {
print("dimensions not compatible");
}
Java could be it, if it had reified generics. You'd create an implementation of Num, or load one from cache, then instantiate the template and attempt to call the mul function.
Or you could abuse the invoke dynamic feature - create specialised functions matrixMultiply$m$n$l and classes Matrix$m$n from some other templating language as needed, then do an invoke dynamic based on type. But this would be very cumbersome to use, I think.
Templates already let you build generic data structures and algorithms when the size of the data on doesn't vary.
reply