12

Is Template Metaprogramming faster than the equivalent C code ? ( I'm talking about the runtime performance) :)

jalf
  • 243,077
  • 51
  • 345
  • 550
n00ki3
  • 14,529
  • 18
  • 56
  • 65
  • 3
    This got downvoted? Seriously? It seems a perfectly good question to me. (although the title and the body of the question seems to ask two different questions, it might be a good idea to clarify which one of them you're interested in) – jalf Jul 25 '09 at 19:07
  • Do you mean "is is faster to program?" or do you mean "does it execute faster?" Your question is ambiguous and we appear to be getting answers to both questions, which is a bit confusing . – Dipstick Jul 25 '09 at 19:31
  • You need to show the two codes, and then we can muse about them. You just cannot ask that question as it stands, it makes no sense. – Johannes Schaub - litb Jul 25 '09 at 19:54
  • I don't have any examples, but i mean it generally.So is quicksort faster than quicksort in C. Or : Is building a Tree is faster than in C... and so on. – n00ki3 Jul 25 '09 at 20:11
  • 1
    I think it makes sense as it is. Of course the answers have to be lot more general than if he had asked about two specific implementations of a given algorithms, but if he'd done that, we could just measure it anyway. For a C programmer curious why C++ people keep going on about template metaprogramming, I think it's a good question. There are some general performance characteristics to generic programming and template metaprogramming that make them useful – jalf Jul 25 '09 at 20:43
  • @n00ki3: I think you misunderstood what TMP is about. Sorting isn't usually done using TMP, although TMP get's (additional) speedups from the same C++ features that speedup the sorting (as already explained by two others). – sbi Jul 25 '09 at 20:48

8 Answers8

28

First, a disclaimer: What I think you're asking about is not just template metaprogramming, but also generic programming. The two concepts are closely related, and there's no exact definition of what each encompasses. But in short, template metaprogramming is essentially writing a program using templates, which is evaluated at compile-time. (which makes it entirely free at runtime. Nothing happens. The value (or more commonly, type) has already been computed by the compiler, and is available as a constant (either a const variable, or an enum), or as a typedef nested in a class (if you've used it to "compute" a type).

Generic programming is using templates and when necessary, template metaprogramming, to create generic code which works the same (and with no loss in performance), with all and any type. I'm going to use examples of both in the following.

A common use for template metaprogramming is to enable types to be used in generic programming, even if they were not designed for it.

Since template metaprogramming technically takes place entirely at compile-time, your question is a bit more relevant for generic programming, which still takes place at runtime, but is efficient because it can be specialized for the precise types it's used with at compile-time.

Anyway...


Depends on how you define "the equivalent C code".

The trick about template metaprogramming (or generic programming in general) is that it allows a lot of computation to be moved to compile-time, and it enables flexible, parametrized code that is just as efficient as hardcoded values.

The code displayed here for example computes a number in the fibonacci sequence at compile-time.

The C++ code 'unsigned long fib11 = fibonacci<11uL>::value', relies on the template metaprogram defined in that link, and is as efficient as the C code 'unsigned long fib11 = 89uL'. The templates are evaluated at compile-time, yielding a constant that can be assigned to a variable. So at runtime, the code is actually identical to a simple assignment.

So if that is the "equivalent C code", the performance is the same. If the equivalent C code is "a program that can compute arbitrary fibonacci numbers, applied to find the 11th number in the sequence", then the C version will be much slower, because it has to be implemented as a function, which computes the value at runtime. But this is the "equivalent C code" in the sense that it is a C program that exhibits the same flexibility (it is not just a hardcoded constant, but an actual function that can return any number in the fibonacci sequence).

Of course, this isn't often useful. But it's pretty much the canonical example of template metaprogramming.

A more realistic example of generic programming is sorting.

In C, you have the qsort standard library function taking an array and a comparator function pointer. The call to this function pointer can not be inlined (except in trivial cases), because at compile-time, it is not known which function is going to be called.

Of course the alternative is a hand-written sorting function designed for your specific datatype.

In C++, the equivalent is the function template std::sort. It too takes a comparator, but instead of this being a function pointer, it is a function object, looking like this:

struct MyComp {
  bool operator()(const MyType& lhs, const MyType& rhs) {
     // return true if lhs < rhs, however this operation is defined for MyType objects
  }
};

and this can be inlined. The std::sort function is passed a template argument, so it knows the exact type of the comparator, and so it knows that the comparator function is not just an unknown function pointer, but MyComp::operator().

The end result is that the C++ function std::sort is exactly as efficient as your hand-coded implementation in C of the same sorting algorithm.

So again, if that is "the equivalent C code", then the performance is the same. But if the "equivalent C code" is "a generalized sorting function which can be applied to any type, and allows user-defined comparators", then the generic programming-version in C++ is vastly more efficient.

That's really the trick. Generic programming and template metaprogramming are not "faster than C". They are methods to achieve general, reusable code which is as fast as handcoded, and hardcoded C

It is a way to get the best of both worlds. The performance of hardcoded algorithms, and the flexibility and reusability of general, parameterized ones.

jalf
  • 243,077
  • 51
  • 345
  • 550
  • jalf I used the sort example in my answer, so +1 for C++ warrior :D – Khaled Alshaya Jul 25 '09 at 19:37
  • 1
    Um, I think there's a huge difference between generic programming and TMP, but I understand that you brought in the GP example to make your point. Still, I'd miss a hint that the comparator isn't TMP. – sbi Jul 25 '09 at 20:43
  • fair point. I added a bit of explanation at the beginning of what GP and TMP are, and mentioned that the sort example would usually be considered GP, but think I'm going to leave it at that. – jalf Jul 25 '09 at 21:03
11

Template Metaprogramming (TMP) is 'run' at compile time, so it's not really comparing apples to apples when comparing it to normal C/C++ code.

But, if you have something evaluated by TMP, then there's no runtime cost at all.

Michael Burr
  • 333,147
  • 50
  • 533
  • 760
4

If you mean reusable code, then yes without a doubt. Metaprogramming is a superior way to produce libraries, not client code. Client code is not generic, it is written to do specific things.

For example, look at the qsort from C standard library, and C++ standard sort. This is how qsort works :

int compare(const void* a, const void* b)
{
    return (*(int*)a > *(int*)b);
}

int main()
{
    int data[5] = {5, 4, 3, 2, 1};

    qsort(data, 5, sizeof(int), compare);
}

Now look at sort :

struct compare
{
    bool operator()(int a, int b)
    { return a < b; }
};

int main()
{
    int data[5] = {5, 4, 3, 2, 1};
    std::sort(data, data+5, compare());
}

sort is cleaner, safer and more efficient because the comparison function is inlined inside the sort. That is the benefit of metaprogramming in my opinion, you write generic code, but the compiler produce code like the hand-coded one!


Another place where I find metaprogramming very beautiful is when you write a library like boost::spirit or boost::xpressive, with spirit you can write EBNF inside C++ and let the compile check the EBNF syntax for you and with xpressive you can write regex and let the compiler check the regex syntax for you also!


I am not sure if the questioner means by TMP calculating values at compile time. This is an example I wrote using boost :)

unsigned long greatestCommonDivisor = boost::math::static_gcd<25657, 54887524>::value;

What ever you do with C you can't mimic the above code, basically you have to hand-calculate it then assign the result to greatestCommonDivisor!

Khaled Alshaya
  • 94,250
  • 39
  • 176
  • 234
  • Well, this is calculating the type at compile-time :) it does not have to be numerical calculations. – Khaled Alshaya Jul 25 '09 at 19:44
  • the questioner didn't define what he meant by "template metaprogramming" and "equivalent C code", so he had to guess anyway. – Johannes Schaub - litb Jul 25 '09 at 19:57
  • When you specialize a template, the compiler calculates the type of the argument, it is not numerical but it is calculation :) – Khaled Alshaya Jul 25 '09 at 19:58
  • I dont think the OP intended a completely rigid distinction between generic programming and template metaprogramming. I think the sort examples answers what he wanted to know, regardless of the exact terminology. +1 – jalf Jul 25 '09 at 20:08
  • Ah, I see now. :) But I still stand my ground that the type is not calculated :) It knows the type. – GManNickG Jul 25 '09 at 20:39
  • I don't know if I'd call Spirit a "beautiful" example of metaprogramming. Fascinating, sure, impressive, definitely, but... Perhaps a bit over the edge. :) – jalf Jul 25 '09 at 21:04
  • I know the EBNF syntax becomes little nasty, but really how can you do it in any other language ;) – Khaled Alshaya Jul 25 '09 at 21:21
  • You can't, but most people would also say you shouldn't. Just saying it's perhaps not the best *real-world* example of TMP being useful. :D – jalf Jul 25 '09 at 21:27
1

The answer is it depends.

Template metaprogramming can be used to easily write recursive descent language parsers and these can be inefficient compared to a carefully crafted C program or a table-based implementation (e.g. flex/bison/yacc).

On the other hand, you can write metaprograms that generate unrolled loops which can be more efficient than a more an conventional C implementation that uses loops.

The main benefit is that metaprograms allow the programmer to do more with less code.

The downside is that it also gives you a gatling gun to shoot yourself in the foot with.

Jeff Leonard
  • 3,284
  • 7
  • 29
  • 27
1

Template metaprogramming can be thought of as compile-time execution.

The compile-time is going to take longer to compile your code since it has to compile and then execute the templates, generate code, then compile again.

The run-time overhead I am not sure about, it shouldn't be much more than if you wrote it yourself in C code I would imagine.

Sean A.O. Harney
  • 23,901
  • 4
  • 30
  • 30
1

I worked on a project where another programmer had tried out metaprogramming. It was terrible. It was a complete headache. I'm an average programmer with a lot of C++ experience, and trying to devise what the hell they were trying to do took way more time than if they had written it straight out to begin with.

I'm jaded against C++ MetaProgramming because of this experience.

I'm a firm believer that the best code is most easily readable by an average developer. It's the readability of the software that is the #1 priority. I can make anything work using any language... but the skill is in making it readable and easily workable for the next person on the project. C++ MetaProgramming fails to pass muster.

Kieveli
  • 10,944
  • 6
  • 56
  • 81
  • 3
    Perhaps the problem was that your associate didn't sufficiently document what his metaprogramming code was doing? Or perhaps he just wasn't very good at writing understandable code. In any case, I'm not sure it's fair to condemn the entire technique based on one experience with one codebase. – Jeremy Friesner Jul 25 '09 at 19:17
  • I agree with Jeremy. Perhaps your coworker wasn't good at writing the code, or doing so cleanly, but I don't think you not being to read it makes it bad. Maybe it *was* written well and you just needed more experience with templates? – GManNickG Jul 25 '09 at 19:29
  • Maybe the code it self didn't lend it self to be metaprogrammed! – Khaled Alshaya Jul 25 '09 at 19:46
  • 1
    Meh, it's the nature of the beast with C++: every time a new feature gets added to the language, the weenies abuse it until something shinier comes along to grab their attention. Like when the language first came out and they were overloading operators left and right. – Ken Keenan Jul 25 '09 at 19:48
  • 1
    Because it's clearly "abuse" to use a generic, efficient sorting function, instead of having to either use an inefficient one, or handcode for *every single* type you want sorted. Yes, I can see how that is "abuse", and makes code harder to read... Of course it can be abused, and of course it can produce unreadable code. But it can also simplify a lot of code that'd otherwise be a mess to look at. – jalf Jul 25 '09 at 20:11
0

I do not think there is any hype, but a clear and simple answer about templates is given by C++ FAQ: https://isocpp.org/wiki/faq/templates#overview-templates

About the original question: it cannot be answered, as those things are not comparable.

Landon
  • 180
  • 10
0

Template metaprogramming does not give you any magical powers in terms of performance. It's basically a very sophisticated preprocessor; you can always write the equivalent in C or C++, it just might take you a very long time.

Nathan Monteleone
  • 5,430
  • 29
  • 43