Nicolás Brailovsky


A modern blog

Archive for the ‘C++’ Category

Design Patterns: C++ Idiom RAII

author Posted by: nico on date Jul 27th, 2010 | filed Filed under: C++, Programming

Ohh design patterns. I love buzzwords. Who doesn’t? To increase my buzzword count I will be writing about a topic most people programming C++ should already know: RAII, resource acquisition is initialization.

Patterns everywhere

Knowing that Gamma et al didn’t list all the known patterns in the universe does come as a surprise to some, not sure why though. The twenty some patterns they write about in their now famous book are (arguably, perhaps) some of the most common design patterns, but the list hardly finishes there.

Some patterns only have meaning in a very specific context; a reactor is a nice pattern for handling asynchronous events yet most applications would never need it. Sometimes “the context” means a specific domain in which the application must work, like a web application, a real time application or a distributed application, sometimes the context is the language itself. RAII falls in this last domain, it only makes sense for C++ applications (actually there are others, but thinking what kind of languages would support this idiom is left as an exercise for the reader).

No, really. What is RAII?

If you made it past that long intro you are probably really interested in knowing what RAII is, and don’t know how to search it in Wikipedia. OK, I’ll explain it the best I can then: RAII means that a resource acquisition is the initialization.

Seriously. That is all the secret there is to RAII. Talking in code:

  1. template
  2. class RAII_Wrapper {
  3.    T *resource;
  4.  
  5.    public:
  6.       RAII_Wrapper (T *resource)
  7.             : resource(resource)
  8.       {
  9.          resource->open();
  10.       }
  11.  
  12.       ~RAII_Wrapper ()
  13.       {
  14.          resource->close();
  15.       }
  16. };

An example

Compare that to a visitor pattern. It’s just too simple to be of any use, isn’t it? Well, contrary to what Java fanboys tend to believe you can do lots of nice things without writing a bazillion lines of code.

  1. int foo() {
  2.         Expensive_Resource x;
  3.         x.open();
  4.  
  5.         try {
  6.                 if (not bar()) {
  7.                         x.close();
  8.                         return -1;
  9.                 }
  10.         } catch () {
  11.                 x.close();
  12.                 throw "up";
  13.         }
  14.  
  15.         int ret;
  16.         try {
  17.                 ret = baz();
  18.         }catch() {
  19.                 // We don’t care, we’re closing x anyway
  20.         }
  21.  
  22.         x.close();
  23.         return ret;
  24. }

Wow… a whole lot of code just for calling bar and baz. And as I wrote that without even compiling I’m sure there are too many hidden bugs, lots of code-paths my simple programmer’s mind can’t even begin to imagine which will cause my Expensive_Resource to be leaked!

Let’s rewrite that using RAII:

  1. void foo() {
  2.         Expensive_Resource x;
  3.         RAII_Wrapper release(&x);
  4.  
  5.         if (not bar()) return -1;
  6.         return baz();
  7. }

A lot nicer, isn’t it? But, what happened to all the try/catch if’s and closes there?

Where’s the magic?

The magic of RAII lies in how C++ handles exceptions. When we have a built object (can an object be in an unbuilt state?) it means it’s constructor has correctly ran. It also means it’s destructor will run when it goes out of scope, doesn’t mater HOW it goes out of scope.

See how brilant that is? Doesn’t matter if a function we’re calling throws, or if we need to return before reaching the end of the function: the destructor will be called and thus our Expensive_Resource will be free!

Why is this C++ specific?

This is an easy one: think how would you implement this in Java: right, you can’t. Not knowing when is your object going to be destroyed means you can’t do anything useful in its destructor, therefore RAII is deeply rooted within the memory management in C++ and it’s pretty much a language specific pattern (or is it?). But, is that so good?

Not everything is so great…

You are probably thinking this is the best discovery since ice cream was invented. Well, not so fast, RAII has it’s detractors too.

The first problem in RAII, it doesn’t have a graceful way of handling resource acquisition failure. If Expensive_Resource is a database, and it’s connection fails, we have a throwing constructor.

Even if throwing constructors are acceptable, throwing destructors may even be a worst idea: throwing while an exception is already active is a cause for concern (tip: it’ll crash your application, doesn’t matter how many try/catch blocks you use, due to stack unwinding issues).

And then, even if we don’t care about throwing destructors you have the issue of a release failure: how do you notify the user that a release failure has occurred? And what do you do, should it happen?

So, RAII is a great idea indeed, and it has it’s uses, but you should be careful when choosing this C++ specific pattern.

Template metaprogramming XI: Hidden Agenda

author Posted by: nico on date Jul 20th, 2010 | filed Filed under: C++, Templates
Wow, number eleven already. We’re getting more chapters here than Final Fantasy games. I didn’t even imagine there was so much to write about such an esoteric language features like templates. I do wonder if anyone will actually read it, but that’s a completly different problem.

Enough meta-meta talk: what can we do with all the things we have learned? We can calculate pi and e, we already showed that as an example on one of the first chapters. This chapter I’m going to write about what motivated me to explore the bizarre underworld of template metaprogramming. Some time ago I had to work with a Berkeley DB researching the feasibility of developing a magic cache for (real) DB table. Leaving aside the discussion of whether this is a good idea (the project did have a good reason to be researched) I hit a major roadblock when trying to provide a façde for every table; something like this: See the problem? To do something like that we’d need a virtual template method, and you can’t have that. After seeing that I thought to myself “Hey, I’ll use templates!”. Then I had two problems, but the damage was done, I couldn’t go back. What kind of contorted device could we implement to make such a devious requirement work? I’ll leave you to think it, the answers I came up with next week.

C++ pretty functions

author Posted by: nico on date Jun 22nd, 2010 | filed Filed under: C++

There are two well known macros from the preprocessor which every macro-sorcer must know. They are __FILE__ and __LINE__. You probably already know about them but anyway, __FILE__ will give you the current file and __LINE__ the current line. Easy, huh?

  1. int main() {
  2.    printf("%s : %i", __FILE__, __LINE__);
  3.    return 0;
  4. }
gccegg-65

The program above would give you “main.cpp : 3″ as a result. There is nothing going on at execution time, it’s all preprocesor wizardy. In fact with “g{++/cc} -E” you can even check what the “real” output is (-E means to return the preprocessor output. Keep in mind a lot of stuff will be included from the headers you use).

  1. int main() {
  2.    printf("%s : %i", "main.cpp", 3);
  3.    return 0;
  4. }

Well that’s nice and all, but g++ can top this easily:

  1. int main() {
  2.    std::cout << __PRETTY_FUNCTION__ << "\n";
  3.    return 0;
  4. }

There are a couple of notable things about this new “pretty function” thing:

  • 1. It will demangle a function’s name
  • 2. This time it isn’t a preprocessor secret thing but a real variable g++ will create.

You can easily use this for better logging functions now (with some macro wizardy, obviously).

Template metaprogramming X: Zero Minus Ten

author Posted by: nico on date Jun 17th, 2010 | filed Filed under: Templates

So far we’ve learned the basic constructs of template metaprogramming (loops, branching, return values) and some basic list operations (getting the length of a list, appending and preppending elements, checking if an element is included in a list). Let’s put it all together by creating an operation to return the position of an element. It’ll be very useful later on too.

If we go back to the Includes operation we can get some help to define the Position operation: the position of an element in a list is one plus the position of the element we’re searching for in the tail, or zero if the head equals said element. The operation is not defined if the element is not in the list.

Translating to pseudo-code:

  1. Position (lst.head, lst) <- 0
  2. Position (e, lst) <- 1 + Position(e, lst.tail)

The translation to C++ is not so trivial this time. Try it, I’ll wait… ready? OK, let’s start

  1. template <class Elm, class Lst> struct Position {
  2.         typedef typename Lst::head Head;
  3.         typedef typename Lst::tail Tail;
  4.         static const bool found = (Head == Elm);
  5.         static const int result = found? 0 : 1 + next;
  6.         static const int next = Position<Elm, Tail>::result;
  7. };

Looks easy… but doesn’t work. First problem, we can’t compare two types, remember? We need to use Eq<X, Y> again. Second problem, although we said the operation is undefined if the element is not included on the list, it would be nice if we could force the compiler to fail if (or when) that happens. Let’s rewrite the operation using a façade again, but adding an Assert:

  1. template <typename Elm, typename LST> struct _Position {
  2.         typedef typename LST::head Head;
  3.         typedef typename LST::tail Tail;
  4.  
  5.         static const bool found = Eq<Elm, Head>::result;
  6.         static const int result = (found)? 0 : 1 + _Position<Elm, Tail>::result;
  7. };
  8.  
  9. template <typename Elm, typename LST> struct Position {
  10.         typedef typename Assert<Includes< Elm, LST >::result>::check include;
  11.         static const int result = _Position<Elm, LST>::result;
  12. };

Oh, we haven’t defined assert yet! There’s another problem, too: even if it won’t compile, the compiler will try to expand _Position< …, NIL > indefinately, causing an error after too many nested template calls. Not nice. We need to add a case to make the compiler stop:

  1. /******************************************************/
  2.  
  3. // Helper: Will fail to compile if the assert is false
  4. class Assertion{};
  5. template <bool cond, class T=Assertion> struct Assert {
  6.         typedef typename T::fail check;
  7. };
  8. template <> struct Assert<true> {
  9.         typedef void check;
  10. };
  11.  
  12. /******************************************************/
  13.  
  14. template <typename Elm, typename LST> struct _Position {
  15.         typedef typename LST::head Head;
  16.         typedef typename LST::tail Tail;
  17.  
  18.         static const bool found = Eq<Elm, Head>::result;
  19.         static const int result = (found)? 0 : 1 + _Position<Elm, Tail>::result;
  20. };
  21.  
  22. // The compiler will try to expand the position check
  23. // after NIL has been reached if this isn’t here
  24. template <typename Elm> struct _Position<Elm, NIL> {
  25.         static const int result = 0;
  26. };
  27.  
  28. template <typename Elm, typename LST> struct Position {
  29.         typedef typename Assert<Includes< Elm, LST >::result>::check include;
  30.         static const int result = _Position<Elm, LST>::result;
  31. };

All that code for such a simple operation, man. Also, see what we did with Assert<>? It seems making a compile fail is actually quite easy. That’s what I have most experience with.

We’ve been through quite a lot, and our toolboox should be quite big already. Next time we’ll start steering towards some sort of aplicability, trying to use some of all these stuff to implement a real, useful and working program… assuming that’s even posible.

Template metaprogramming IX: Absolute Zero

author Posted by: nico on date Jun 10th, 2010 | filed Filed under: C++, Templates

By now we should have learned how to perform loops, branching and returns using templates. Let’s add a couple of useful operations to our library: append and prepend.

Prepending an element to a list is very easy: the result is a list (oh surprise) consisting of a head (the element we want to add) and a tail (the old list). In the pseudocode I’ve been using so far:

  1. Prepend(e, lst) <- LST(e, lst)

And in C++ (trivial, this time):

  1. template <typename Elm, typename Lst=NIL> struct Preppend {
  2.         typedef LST<Elm, Lst> result;
  3. };

Appending is a little bit more difficult, as we need to first find the end of the list. Think for a second how would you define it… back? Ok, I’d define it this way: appending an element to the list yields a list, consisting of the same head and the result of appending said element to the tail. The null case, as usual, is appending an element to a NIL list; in this case the result is a list with the element itself. So:

  1. Append(e, NIL) <- LST(e)
  2. Append(e, lst) <- LST(lst.head, Append(e, lst.tail))

Looks complicated what it follows the same structure as the rest of the basic-ops:

  1. template <class Elm, class Lst> struct Append {
  2.         typedef typename Lst::head Head;
  3.         typedef typename Lst::tail Tail;
  4.  
  5.         typedef typename Append<Elm, Tail>::result Next;
  6.         typedef typename LST<Head, Next>::result result;
  7. };
  8.  
  9. template <class Elm> struct Append<Elm, NIL> {
  10.         typedef LST<Elm> result;
  11. };

Easy. Now, what happens if we want to add a default value for Lst, so we can use Append to create lists? Easy too, but we need a façade this time; just rename Append to _Append, then

  1. // This is here just because I wanted a default param :D
  2. template <typename Elm, typename Lst=NIL> struct Append {
  3.         typedef typename _Append<Elm, Lst>::result result;
  4. };

I promised to add one more operation to our toolbox, returning the position of an element, but this post is getting quite long and I’m afraid it may be too much for the average attention span of a programmer… we’ll leave it for next time.

Template metaprogramming VIII: A Rough Whimper of Insanity

author Posted by: nico on date Jun 3rd, 2010 | filed Filed under: C++, Templates

Remember last time? We learned how to get the lenght of a list. This time I’ll introduce some more of these basic ops. Let’s begin with “Nth”: getting the Nth element of a list; which, remember, in this case is a type, not a concrete element. This means the Nth element will be something like int, char, const char*, not 1, 2 or 3. We introduced a trick to get around this limitation before using a template <int>, go there to refresh your memory if needed.

So, what would the coloquial definition of “Nth” be? I’d put it like “The operation Nth for a list equals the head of the list for N = 0 and Nth (minus one) of tha tail otherwise”. A little bit more formally:

  1. Nth(0, lst) <- lst.head
  2. Nth(n, lst) <- Nth(n-1, lst.tail)

Translating this to C++ should be a breeze to you now. Try it, I’ll wait. Read? OK, this is MY answer:

  1. template <typename LST, int N> struct Nth {
  2.         typedef typename LST::Tail Tail;
  3.         typedef typename Nth<Tail, N-1>::result result;
  4. };
  5.  
  6. template <typename LST> struct Nth<LST, 0> {
  7.         typedef typename LST::head result;
  8. };

Though the structure is very similar to the previous “basic operation”, getting the length of a list, the concept is quite different. This time we’re defining a return type recursivly. Anyway, it was too easy indeed, let’s try a more complex operation now.

How can we check if an element exists on a list? Seems easy enough, an element is included in a list if the head equals the element itself or if the element is included in the tail. In the pseudo language I just invented:

  1. Includes(lst.head, lst) <- true
  2. Includes(e, lst) <- Includes(e, lst.tail)

Looks easy, right? Well, there’s a bug there, can you spot it? Yeah, we’re missing the false condition. We should add a third spetialization:

  1. Includes(lst.head, lst) <- true
  2. Includes(e, NIL) <- false
  3. Includes(e, lst) <- Includes(e, lst.tail)

Again, let’s translate the pseudocode to C++. Try it, I’ll wait. Read? OK, this is MY answer:

  1. template <class Elm, class Lst> struct Includes {
  2.         typedef typename LST::head Head;
  3.         typedef typename LST::tail Tail;
  4.  
  5.         static const bool found = (Elm == Head);
  6.         static const bool found_tail = Includes<Elm, Tail>::result;
  7.         static const bool result = found || found_tail;
  8. };
  9.  
  10. template <class Elm> struct Includes <Elm, NIL> {
  11.         static const bool result = false;
  12. };

Looks nice, doesn’t it? Too bad it won’t work, you can’t compare two types. What would (int == char) mean in C++? We need a helper there, some kind of trick to compare to types. We can use partial template spetialization again:

  1. template <class X, class Y> struct Eq { static const bool result = false; }
  2. template <class X> struct Eq<X, X> { static const bool result = true; }

With this little struct now we can write our include operation this way:

  1. template <class Elm, class Lst> struct Includes {
  2.         static const bool result =
  3.                                 Eq<Elm, typename LST::head>::result
  4.                                  || Includes<Elm, typename LST::tail>::result;
  5. };
  6.  
  7. template <class Elm> struct Includes<Elm, NIL> {
  8.         static const bool result = false;
  9. };

Very esoteric looking, the right mix of Haskel, C++ and booze to ensure job security for life. Next time we’ll find a way to search for the position of an element, a somewhat more complicated task.

Oh shit, the stack

author Posted by: nico on date Jun 1st, 2010 | filed Filed under: C++, Grumpy

* Post from the wayback machine. I wrote this a long time ago but it got way down the posts queue, don’t know why *

I liked my vacations very much, thank you. Some people enjoyed vacations from me too. At work they even decided to keep until my return. Upon my arrival a nice coredump was waiting at my desk, so to speak. Check it out, isn’t it beautiful?

  1. 0 0xff05d070 in inflate_fast () from /usr/lib/libz.so
  2. 1 0xff05a13c in inflate () from /usr/lib/libz.so
  3. 2 0×00146224 in ZDecompress::decompress (this=0xfbc7b300, sauce=@0xfbe7b740, dest=@0×27c910) at Compressor.h:134
  4. 3 0×00145e80 in HandleClient::get_client_data (this=0×27c810, output_stream=0×27c910) at IPC/DataReceiver.cpp:54

Yeah, that’s getting killed inside zlib. Nice way to start the year, a bug in zlib. What led me to that conclusion? Easy, the same compressed file worked in Ubuntu. Must be a bug in zlib then!

The next step was getting zlib’s code and adding enough printf’s to know the problem was in the middle of the file, not at the beginning nor the end; indeed, most of the file could be correctly decoded, but then it just died. This looked more and more like a bug in zlib.

I began to scramble things around, trying to isolate the problem. Things just got weirder, the same code worked fine if instead of being inside a thread I was on the main thread. If you have psychic powers you now have enough information to know what the problem was. Although I should have known too (these wasn’t even the first time I saw a problem like this one!) I was mind set on finding a bug in zlib, which now, it seems, only appears while interacting with ACE (in my defense, I did see these kind of bugs too).

Fiddling around with the code some more, even stranger backtraces began to appear. First this one:

  1. Program received signal SIGSEGV, Segmentation fault.
  2. [Switching to LWP 10]
  3. 0xfd6b88fc in _pollsys () from /usr/lib/libc.so.1
  4. (gdb) bt
  5. #0  0xfd6b88fc in _pollsys () from /usr/lib/libc.so.1
  6. #1  0×696e7661 in ?? ()
  7. #2  0×696e7661 in ?? ()

And then this other one, which led me into the right direction:

  1. Program received signal SIGSEGV, Segmentation fault.
  2. [Switching to LWP 9]
  3. 0×000b6784 in std::operator| (__a=Cannot access memory at address 0xfbb7b094
  4. )
  5.     at /usr/local/lib/gcc/sparc-sun-solaris2.10/3.4.6/../../../../include/c++/3.4.6/bits/ios_base.h:124
  6. 124       { return _Ios_Openmode(static_cast(__a) | static_cast(__b)); }
  7. (gdb) bt
  8. #0  0×000b6784 in std::operator| (__a=Cannot access memory at address 0xfbb7b094
  9. )
  10.     at /usr/local/lib/gcc/sparc-sun-solaris2.10/3.4.6/../../../../include/c++/3.4.6/bits/ios_base.h:124
  11. #1  0×00152d5c in HandleClient::get_client_data (this=Cannot access memory at address 0xfbb7b088
  12. ) at IPC/DataReceiver.cpp:46

That last stack trace got me to think how could it be possible for an otherwise working program to coredump while creating an stdlib object. I mean, stdlib is quite well tested, isn’t it? Then it struck me: the keyword isn’t stdlib but creating. It was allocating memory from the stack, upon entering the function.

Some more research later I found out that Solaris default thread size is about 1 mb, while in Ubuntu this thread is of about 8 mb. And I also noticed the buffer I was allocating for zlib was taking up space in… the stack.

If there’s something to learn from this story is that you should always know what goes in the stack: only small objects should live there, and you should always know the max stack depth a function could reach. Otherwise it may come back and bite you in the ass when you’re back from your vacations.

Template metaprogramming VII: The Enemy Within

author Posted by: nico on date May 27th, 2010 | filed Filed under: Templates

Remember where were we last time? We had this code to define a list:

  1. struct NIL {
  2.         typedef NIL Head;
  3.         typedef NIL Tail;
  4. };
  5.  
  6. template  struct LST {
  7.         typedef H Head;
  8.         typedef T Tail;
  9. };
  10.  
  11. template  Int{ static const int result = N; };
  12. typedef Lst< Int<1>, Lst< Int<2>, Lst< Int<3> > > > OneTwoThree;
Now, to increase our template-foo, let’s practice some basic operations. The same operations you would implement to practice your skill any other functional language. If I remember correctly these where useful when learning Haskel: getting a list’s lenght, getting the Nth element, appending and preppending elements… that sort of stuff.

Let’s start with the most basic: getting the length of a list. We don’t really have a for loop so using recursion is the only way. It gets easier if we think again on our definition of list: “think of a list as tuple, two elements, the first (called head) will be the first element of the list and the second element as another list or a NIL object”. Whit this definition of a list, then it’s length turns to be 1 (the head) + the length of the remaining list (the tail), with a special case for the length of a NIL object which should always be 0. In template-speak:

  1. template  struct Length {
  2.         typedef typename LST::Tail Tail;
  3.         static const unsigned int tail_lenth = Length< Tail >::result;
  4.         static const unsigned int result = 1 + tail_length;
  5. };
  6.  
  7. template <> struct Length  {
  8.         static const unsigned int result = 0;
  9. };

I know. You are thinking “wait, what?”. Well, even for this basic case we need to use some esoteric language features:

  • typename is needed to tell the compiler LST::Tail is a type and not a static variable (like Length::result is). Did you remember that from chapter IV?
  • We have to use recursive templates, but you probably already figured that out. You should remember this from chapter II.
  • We can provide a spetialization of a template. You should also remember this from chapter II.

Obviously, you can write it this way too:

  1. template  struct Length {
  2.         static const unsigned int result = 1 + Length< typename LST::Tail >::result;
  3. };
  4. template <> struct Length  {
  5.         static const unsigned int result = 0;
  6. };

The rest of the “basic” list-operations are quite similar, but I’ll leave that for another post.

Template metaprogramming VI: The Spider Webb

author Posted by: nico on date May 20th, 2010 | filed Filed under: Templates
We have been building our template meta-foo for five chapters now, and I think we are ready to move on to more advanced topics. We will be borrowing a lot more from functional languages from now on, so you may want to actually start practicing some template metaprogramming to keep advancing.

In our previous entries we worked with basic building blocks, making it quite easy to keep in mind the whole “program flow”. Now it won’t be so easy anymore, as we’ll be using real metaprogramming (i.e. templates operating on templates) so a lot more thought will be needed for each program.

Another point to keep in mind, you don’t have a debugger here. All the magic occurs at compile time so there is no gdb to step through your program to find a logic flaw. There’s a little trick to check if you are too far off from the target but, mainly, you’ll have to think for yourself.

Let’s start with any functional programming course basics: lists. We have to think, first, how can a list make any sense when you only have types and no values. It means you can have a list like “int, char, void**, Foo”, and not something like “1, 2, 3″. Or, can you? There’s a way to trick the compiler into creating a type from a integral value:

  1. template  struct Int {
  2.         static const int value = N;
  3. };

Voila! Now you can create a list of numbers. For our next trick, let’s implement the list itself. No pointer magic, think of a functional definition of a list. Come on, I’ll wait… ready? OK, a list is a tuple T of two values, in which the first element, called head, is the first element of the list and the second element, called tail, is either a list or the NULL element.

Quite a mouthful… let’s go over that definition again:

  1. // A list is a tuple T of two values
  2. List: [ …, … ]
  3.  
  4. // in which the first element, called head, is the first element of the list
  5. List: [ Head, … ]
  6.  
  7. // and the second element, called tail,
  8. List: [ Head, Tail]
  9.  
  10. // is either a list or the NULL element
  11. List: [ Head, Tail]
  12. Tail: List | Nil

So, as an example, a list of numbers could be expressed as:

  1.         List( 1, List( 2, List( 3, NIL ) ) )

Closing up… how would you define this list in C++? Easy:

  1. template  LST {
  2.         typedef H Head;
  3.         typedef T Tail;
  4. };

We need here a NIL type to use as a list ending element. We could also use a default template type, so we won’t have to write the last NIL to end a list definition. Thus we have now:

  1. struct NIL {
  2.         typedef NIL Head;
  3.         typedef NIL Tail;
  4. };
  5.  
  6. template  struct LST {
  7.         typedef H Head;
  8.         typedef T Tail;
  9. };

Nice. You should remember the following rules:
1. We can use template to define a template class, defining a new type based on a number instead of another type ;)
2. We can’t “store” a value in a type… unless we store it as a static value, that is.
3. Using a convention for defining result holding variable names is very useful, as there are no interfaces and more than once we’ll be using a result from an unknown class

With that said, let’s translate the list (1, 2, 3) to Tmpl C++

  1. template  Int{ static const int result = N; };
  2. typedef Lst< Int<1>, Lst< Int<2>, Lst< Int<3> > > > OneTwoThree;

Not so bad to start with. Next time we’ll be doing something a little bit more useful with this list.
One last note, initializing a static const int in the definition of the class may be non portable (some compilers seem to have trouble with it). An enum may be used instead.

Template metaprogramming V: Face to face

author Posted by: nico on date May 12th, 2010 | filed Filed under: C++, Templates
By now we have learned the basics for a nice template metaprogramming toolkit:

  • Loops with recursive template definitions
  • Conditionals with partial template specializations
  • Returns using typedefs

Unfortunately that’s all you need for a Turing complete language, meaning now we have the power, bwahahaha! Mph, I’m sorry, back on topic, it means we can now create a fully functional and useful template metaprogramming device… for approximating e, nonetheless. Oh, you think that’s not useful? Well though luck, that’s all you get for now:

  1. template  struct Frak {
  2.         static const long Num = N;
  3.         static const long Den = D;
  4. };
  5.  
  6. template  struct MultEscalar {
  7.         typedef Frak< N*X::Num, N*X::Den > result;
  8. };
  9.  
  10. template  struct IgualBase {
  11.         typedef typename MultEscalar< X1, Y1::Den >::result X;
  12.         typedef typename MultEscalar< Y1, X1::Den >::result Y;
  13. };
  14.  
  15. template        struct MCD {
  16.         static const long result = MCD::result;
  17. };
  18. template  struct MCD {
  19.         static const long result = X;
  20. };
  21.  
  22. template  struct Simpl {
  23.         static const long mcd = MCD::result;
  24.         typedef Frak< F::Num / mcd, F::Den / mcd > result;
  25. };
  26.  
  27. template  struct Suma {
  28.         typedef IgualBase B;
  29.         static const long Num = B::X::Num + B::Y::Num;
  30.         static const long Den = B::Y::Den; // == B::X::Den
  31.         typedef typename Simpl< Frak >::result result;
  32. };
  33.  
  34. template  struct Fact {
  35.         static const long result = N * Fact::result;
  36. };
  37. template <> struct Fact<0> {
  38.         static const long result = 1;
  39. };
  40.  
  41. template  struct E {
  42.         // e = S(1/n!) = 1/0! + 1/1! + 1/2! + …
  43.         static const long Den = Fact::result;
  44.         typedef Frak< 1, Den > term;
  45.         typedef typename E::result next_term;
  46.         typedef typename Suma< term, next_term >::result result;
  47. };
  48. template <> struct E<0> {
  49.         typedef Frak<1, 1> result;
  50. };
  51.  
  52. #include
  53. int main() {
  54.         typedef E<8>::result X;
  55.         std::cout << "e = " << (1.0 * X::Num / X::Den) << "\n";
  56.         std::cout << "e = " << X::Num <<"/"<< X::Den << "\n";
  57.         return 0;
  58. }

Looking nice, isn’t it? You should have all what’s needed to understand what’s going on there. Even more, almost everything has been explained in previous articles, with the exception of EqBase. But that’s left as an exersice for the reader because the writer is too lazy.

If you think any part of the code requires clarification ask in the comments. Next, a long overdue topic: lists using template metaprogramming. Guaranteed to blow your mind into little pieces!