Maybe a touch harsh :)
Oh, you know I wrote that with loving condescension, as I usually do! ;)
I thought when I saw templates they were to do with providing type-"independent" generic functions, aka "generics", e.g. in C#.
Well, yes, templates are for that - providing type independent code, or rather as you put it generic, because there may be limitations put on the types involved (i.e. the type may be required to be floating point, or integral). This is fine and very useful for many purposes. Consider writing an algorithm that operates on a matrix, the matrix may contain rational numbers, or floating point, or complex, or quaternions. The point is the algorithm is the same regardless of the type it operates on (with some sane limitations).
C# isn't a good example as it doesn't compile to native assembly. It has, much like its mother Java, an interpreter for opcode. That is, source is compiled to an intermediary opcode (which is similar to assembly), which is then interpreted by a virtual machine.
Nothing to do with in-lining....
Well, not nothing. Templates' instantiations are known fully, including all dependent types and the whole source. While you can have them hidden in a source file and prevent inlining, that's an extremely rare case. Usually the point of them being stored in the headers without exposing only the instantiated types is to allow the compiler to freely inline everything it wants to. So they're also used to hint that to the compiler. In this case that's the idea, otherwise you'd just write the simple fast exponentiation which takes 2 arguments (i.e. basically a rewrite of std::pow) instead of giving the compiler enough rope to hang itself. As I said, every instantiation is different, so the compiler is going to generate one function for each template argument, so calling power<8>, leads to your compiler generating code for power<8>, power<4>, power<2>, power<1> and so on. These are separate functions, mind you. Then it may (or may not) decide to inline some (or all) of them into the others.