いま流行のFizzBuzzを純粋関数型言語C++で書いてみた

73行。boost/mplやboost/lambda駆使すれば20行くらいになるかな?
なんかあんまり純粋関数な感じしないんだよね微妙。

template<bool cond,typename th,typename el>
struct if_;
template<typename th,typename el>
struct if_<true,th,el> {
  typedef th result;
};
template<typename th,typename el>
struct if_<false,th,el> {
  typedef el result;
};

template<int n>
struct int_{};

struct fizz {static const char* str;};
struct buzz {static const char* str;};
struct fizzbuzz {static const char* str;};
const char* fizz::str="Fizz";
const char* buzz::str="Buzz";
const char* fizzbuzz::str="FizzBuzz";

struct filter {
  template<int n>
  struct exec {
    typedef
      typename if_<n%15==0, fizzbuzz,
      typename if_<n%3==0,fizz,
      typename if_<n%5==0,buzz,
      int_<n> >::result >::result >::result result; //cooool!!
  };
};

template<typename t>
struct to_value {
  static inline const char* get() { return t::str; }
};

template<int n>
struct to_value<int_<n> > {
  static inline int get() { return n; };
};

#include <iostream>
using std::cout;
using std::endl;

template<int start,int end>
struct int_sequence {
  static const int value=start;
  typedef int_sequence<start+1,end> next;

  template<typename body>
  inline static void print_each() {
    //このbody::template execって記法がわかんなかったんだよ。今回唯一の収穫
    cout << to_value<typename body::template exec<value>::result>::get() << " ";
    next::template print_each<body>();
  }
};

template<int start_end>
struct int_sequence<start_end,start_end> {
  static const int value=start_end;
  typedef void next;
  template<typename body>
  inline static void print_each() {
    cout << to_value<typename body::template exec<value>::result>::get();
  }
};

int main() {
  int_sequence<1,100>::print_each<filter>();
  cout << endl;
}

このコードをコンパイルすると、なんと!

int main() {
  cout << 1 << " ";
  cout << 2 << " ";
  cout << "Fizz" << " ";
  //(snip)
  cout << 98 << " ";
  cout << "Fizz" << " ";
  cout << "Buzz";
  cout << endl;
}

と等価なコードが出力されます。


何が嬉しいんだ。


剰余を使わないバージョンもかいてみた(inspired by http://d.hatena.ne.jp/cxx/20070517/1179341986 )

template<typename car,typename cdr> 
struct cons{
  typedef car car; //あ、通るんだこれ
  typedef cdr cdr;
};

struct num {static int get(int n){return n;}};
struct fizz {static const char* get(int){return "Fizz";}};
struct buzz {static const char* get(int){return "Buzz";}};
struct fizzbuzz{static const char* get(int){return "FizzBuzz";}};

typedef cons<num,cons<num,cons<fizz,
        cons<num,cons<buzz,cons<fizz,
        cons<num,cons<num,cons<fizz,
        cons<buzz,cons<num,cons<fizz,
        cons<num,cons<num,cons<fizzbuzz,void>>> >>> >>> >>> >>> fb; //これはひどい

#include <iostream>
using std::cout;
using std::endl;

template<int c,typename j>
struct FizzBuzz {
  template<typename list> struct next {typedef typename list::cdr result;};
  template<typename car> struct next<cons<car,void>> {typedef fb result;};
  static void exec() {
    cout << j::car::get(c);
    FizzBuzz<c+1,next<j>::result>::exec();
  }
};

template<typename j>
struct FizzBuzz<101,j> {
  static void exec() {}
};

int main() {
  FizzBuzz<1,fb>::exec();
  cout << endl;
}

なんか凄く短くなった><