Adam Tornhill - Software Development Pages, Articles Section | ||||
|
|
Using C++ template metaprogramming, I'll try to solve FizzBuzz by having the compiler output the solution as error messages. FizzBuzz? The hilarious drinking game? Well, almost. It all started with a blog by Imran on how FizzBuzz was used during interviews to weed out programmers that, believe it or not, cannot program. The interview question was put like this: “Write a program that prints the numbers from 1 to 100. But for multiples of three print “Fizz” instead of the number and for the multiples of five print “Buzz”. For numbers which are multiples of both three and five print “FizzBuzz”.” Simple enough, but FizzBuzz proved to be scarily effective in eliminating programmers that actually cannot produce software. During the lengthy discussions that followed, a lot of creative solutions to FizzBuzz were posted. They ranged from over-engineered Java to down-to-the-metal Assembler, wicked Perl one-liners, and XSLT solutions. Of course I want to be a part of this rising FizzBuzz industry! Here’s my starting points: 1. Pure functional languages are cool, I'll try to glue it all together in C++. In fact I’m going to use a particularly evil corner of the language: templates. Metaprograms in C++ execute at compile-time and are indeed pure functional. Now, a fundamental requirement on FizzBuzz is that it prints the results. Printing in a pure functional language isn’t easy. I may be manager-material, because I’ll try to delegate this tricky problem. Who’ll get it? Well, I have a very expensive compiler in Microsoft’s Visual Studio 2005, so why not get some value for my money and have the compiler do the hard work? Here’s my first shot:
template<int i> struct RunFizzBuzz { typedef vector<int_<i> > Number; typedef typename if_c<(i % 3 == 0) && (i % 5 == 0), FizzBuzz, typename if_c<i % 3 == 0, Fizz, typename if_c<i % 5 == 0, Buzz, Number>::type>::type >::type t1; typedef typename push_back<typename RunFizzBuzz<i - 1>::ret, t1>::type ret; }; template<> struct RunFizzBuzz<0> // Terminate the recusion. { typedef vector<int_<0> > ret; }; int main() { typedef RunFizzBuzz<100>::ret::compilation_error_here res; } This program is impossible to outperform with respect to run-time performance; it will actually never run! And here’s the nice touch: the program will deliberately not even compile! The interesting part is that as error message, the compiler outputs the FizzBuzz solution. Look at the highlighted parts below: \Main.cpp(36) : error C2039: 'compilation_error_here' : is not a member of 'boost::mpl::vector101 <SNIP long argument list>' How it worksIn C++ template metaprogramming, loops are implemented using recursive
template instantiations ( Exit PortabilityThat's it. A complete FizzBuzz solution written by Visual Studio 2005.
Besides a horrific compilation time, the program has the following drawbacks: April 2007
|
©2005 Adam Tornhill | adam@adamtornhill.com |