Hacker News new | comments | show | ask | jobs | submit login
Solving FizzBuzz with C++ compiler error messages (adampetersen.se)
113 points by ranit8 on Apr 21, 2012 | hide | past | web | favorite | 30 comments



How about a solution for primes below a number using Sieve of Eratosthenes:

  template<int H=-1, typename T=void>
  struct tl {
      enum {head=H};
      typedef T tail;
  };
  
  template<>
  struct tl<> {
  };
  
  template<int N, typename Then, typename Else>
  struct if_c {
      typedef Then type;
  };
  
  template<typename Then, typename Else>
  struct if_c<false, Then, Else> {
      typedef Else type;
  };
  
  template<int N, typename SoFar>
  struct is_prime {
      enum {value = N%SoFar::head && is_prime<N, SoFar::tail>::value};
  };
  
  template<int N>
  struct is_prime<N, tl<>> {
      enum {value = 1};
  };
  
  template<int N, int C, typename SoFar=tl<>>
  struct prime {
      typedef typename prime<N+1, C-1, typename if_c<is_prime<N, SoFar>::value, tl<N, SoFar>, SoFar>::type>::type type;
  };
  
  template<int N, typename SoFar>
  struct prime<N, 0, SoFar> {
      typedef SoFar type;
  };
  
  template<int N>
  struct number : prime<2, N-2> {
  };
  
  template<>
  struct number<0> {
  };
  
  template<>
  struct number<1> {
  };
  
  template<typename T>
  struct print {
  };
  
  void main() {
      typedef print<number<300>::type>::type type;
  }

Here is result from Visual Studio 2005:

  c:\console.cpp(113) : error C2039: 'type' : is not a member of 'print<T>' with [T=tl<293,tl<283,tl<281,tl<277,tl<271,tl<269,tl<263,tl<257,tl<251,tl<241,tl<239,tl<233,tl<229,tl<227,tl<223,tl<211,tl<199,tl<197,tl<193,tl<191,tl<181,tl<179,tl<173,tl<167,tl<163,tl<157,tl<151,tl<149,tl<139,tl<137,tl<131,tl<127,tl<113,tl<109,tl<107,tl<103,tl<101,tl<97,tl<89,tl<83,tl<79,tl<73,tl<71,tl<67,tl<61,tl<59,tl<53,tl<47,tl<43,tl<41,tl<37,tl<31,tl<29,tl<23,tl<19,tl<17,tl<13,tl<11,tl<7,tl<5,tl<3,tl<2,tl<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>]


Couldn't help but notice you're one of those void main people..


You wouldn't pass, because you didn't read the specs!

"prints the numbers from 1 to 100." -- you printed 0-100! ;-)

Just kidding, nice solution. Show's nicely how terrible and awesome the precompiler is.


> You wouldn't pass, because you didn't read the specs!

> "prints the numbers from 1 to 100." -- you printed 0-100! ;-)

This is specifically addressed in the "Exit Portability" section:

"1. It starts at 0 instead of 1. This is just to make the output more readable by having the number encoded in the template argument (T0, T1, T2, etc) map directly to its FizzBuzz representation. If you want a strict version of FizzBuzz, just change the template specialization to terminate on '1' and return a vector<int_<1> > instead."


That's not actually the precompiler. The "precompiler" in C++ is the pre-processor, which just does straightforward text substitution. Template metaprogramming uses (abuses) the compiler itself. Templates in C++ are Turing Complete: http://netvor.sk/~umage/docs/3rdparty/C++%20Templates%20are%...


oh, sorry for the terminology glitch. Know about turing completeness, have used it for optimizing execution speed of programs and making TAs go insane.


Um, nope, it is within the spec. The spec doesn't mention not printing other numbers. He met the req of printing 1-100 (he just also happened to print 0).


By this logic, the following would also be an acceptable solution:

    cat /dev/random > fizzbuzz.txt


Also gets 0 wrong. It should be a FizzBuzz.


Cool! If I needed a C++ guy, that'd be an instant hire (though he wouldn't do any meta-programming for me!).

Wondering how this works out in g++ or other compilers?


How about Perl:

  #!/usr/bin/perl
  $n = 100;

  open(FH, '>touch') and print FH '' and close FH;
  push @ARGV, "Fizz$_" for (1..$n/3);	#push some fizz's
  push @ARGV, "Buzz$_" for (1..$n/5);	#push some buzz's
  push @ARGV, $_ for (1..$n);		#we'll sort it all out later

  1 while ($_ = shift and @ARGV and !fork);  #let the games begin

  if (/Fizz(\d+)/) {
     sleep $1 * 9;
     open (FH, '>>touch') and print FH "Fizz" and close (FH); 
     }

  elsif (/Buzz(\d+)/) {
     sleep $1 * 15 + 1;
     open (FH, '>>touch') and print FH "Buzz" and close (FH); 
     }

  else {
     sleep $_ * 3 + 2;
     open(FH, 'touch') and @lines = <FH> and close (FH);
     open(FH, '>touch') and print FH '' and close FH;
     print @lines ? @lines : $_, "\n";
     }

What do you think? I didn't bother cleaning up the file access. Nefarious though isn't it.


Awful and awesome at the same time. It reminds me quite a bit of FizzBuzz implemented in Haskell's type system (http://blog.omega-prime.co.uk/?p=28).


Nice. Before I read that the article you linked, I had a small mental wager with myself, that Oleg would be mentioned.


This is beautiful in it's terrible-ness. I think it's safe to say I wouldn't hire anyone that produced this during an interview. It would be impossible to tell if they were mad scientist crazy or just too dense to understand the point of the interview.


What I would take away from this mad display:

1. The candidate has a solid understanding of the template system in C++. Chances are pretty high that he has a similarly high understanding of other parts (which would come out with further discussions during the interview).

2. The candidate is a creative thinker, which is hugely important in a profession where you tend to get blocked by faulty or incomplete tools, or tools not designed for what you want to do.

3. The candidate is highly intelligent and inquisitive, which means he'll likely have more success in exploratory tasks, and he'll likely have a greater breadth and possibly depth of exposure in general.

4. The candidate can program (of course).


5. Candidate likely has a pretty good sense of humour.


That is the advantage of face to face... It would be obvious they rejected the trivial solution, and went for something fun. I would be thinking mad scientist about 3 min in and wondering how much they are going to scare the rest of the team. Well done.


Just had a case of Baader-Meinhof. I did an interview last week and I was asked to do the FizzBuzz test in PHP. I'd never heard of it, thought it was a cool question though. Glad to see I produced the text book answer though!


You were a German left-wing terrorist?



FizzBuzz is not so much cool, but a small test to filter out people who can't program at all. (So it's actually sad.)


How is it "a cool question" by any metric? It's a mock question.


I don't see the value in producing an error instead of using the meta-program to produce an unrolled loop with mpl::for_each that actually prints the sequence at run-time. ;)

Seriously, the MPL is a powerful and surprising beast but in most cases some preprocessor library like Boost.Preprocessor or Chaos is unavoidable to really make it useful. In fact, you can write this complete program with the preprocessor and I would actually prefer it (or const expression meta-programming).


The next person that claims that C++ is a good language is getting a link to this.

Yes, I program my projects in C++. No, it is not okay.


If anything, this article supports the claim that C++ is a good language. The fact that C++ templates are Turing-complete and allow for this kind of thing is pretty darn cool in my opinion.


Food for thought: That means whether an arbitrary c++ program compiles reduces to the halting problem.

I would wager that for the vast majority of real situations you'd be better off writing that in the primary language and either bundling the precomputed result when you package your application or running it at runtime.

I'm sure there is a small class of trivial exceptions, but no non-trivial ones.


Put differently, I can't even guarantee that my program finishes compiling. That's dumb.

Brainfuck is Turing-complete too, you know. It's not a good language either.


Reminds me of when I was starting to program many (many, many) years ago and, for an exercise, I wrote IBM 7094 macro assembly language that would output the primes up to any specified value. The result was in a 7094 assembly time array.


Recently someone on the Boost mailing list posted a version of the famous "99 Bottles of Beer" using Boost.MPL: https://gist.github.com/1130306


I love it when it comes to make new ideas.




Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact

Search: