剰余を使わないFizzBuzzを純粋関数型言語C++で書いてみた
こないだのエントリにも書いたけど。つづき。
ルール・剰余使わない・実行時に行なうのはI/Oのみ(数列の生成も条件分岐もコンパイルタイムに処理する)
#include <iostream> using std::cout; using std::endl; template<int c,int fiz,int buz> struct FizzBuzz { static void exec() { cout << c; FizzBuzz<c+1,fiz+1,buz+1>::exec(); } }; template<int c> struct FizzBuzz<c,3,5> { static void exec() { cout << "FizzBuzz"; FizzBuzz<c+1,1,1>::exec(); } }; template<int c,int buz> struct FizzBuzz<c,3,buz> { static void exec() { cout << "Fizz"; FizzBuzz<c+1,1,buz+1>::exec(); } }; template<int c,int fiz> struct FizzBuzz<c,fiz,5> { static void exec() { cout << "Buzz"; FizzBuzz<c+1,fiz+1,1>::exec(); } }; template<int fiz,int buz> struct FizzBuzz<101,fiz,buz> {static void exec(){}}; int main() { FizzBuzz<1,1,1>::exec(); cout << endl; }
fizbuzがいっぱいでてくるのを分離して共通部分を徹底的にくくりだしてほげほげ
#include <iostream> using std::cout; using std::endl; template<typename d,int max,int n> struct outbase { static bool out() {return false;} static const int next=n+1; }; template<typename d,int max> struct outbase<d,max,max> { static bool out() { cout << d::msg();return true;} static const int next=1; }; template<int n> struct fizz : outbase<fizz<n>,3,n> { static const char* msg(){return "Fizz";} }; template<int n> struct buzz : outbase<buzz<n>,5,n> { static const char* msg(){return "Buzz";} }; template<int c,int fiz,int buz> struct FizzBuzz { static void exec() { (fizz<fiz>::out() + buzz<buz>::out()) || cout << c; FizzBuzz<c+1,fizz<fiz>::next,buzz<buz>::next>::exec(); } }; template<int fiz,int buz> struct FizzBuzz<101,fiz,buz> {static void exec(){}}; int main() { FizzBuzz<1,1,1>::exec(); cout << endl; }
(fizz<fiz>::out() + buzz<buz>::out()) || cout << c;
これがかなりギリギリ。out()が返す値はコンパイル時に決定可能なので最適化が効けば条件分岐は生成されないと思うのだが言語仕様的にどうなのだろう。
そして静的条件分岐にはテンプレマッチング以外の方法もあると気付く
template<typename d,int max,int n> struct outbase { static const bool cond=n==max; static bool out() {if(cond) cout << d::msg(); return cond;} static const int next=cond?1:n+1; };
継承よりマクロのほうがよくね?
#include <iostream> using std::cout; using std::endl; #define DEF(name,cycle) \ template<int n> \ struct name { \ static const bool cond=n==cycle; \ static bool out() { if(cond)cout<<#name;return cond; } \ static const int next=cond?1:n+1; \ } DEF(Fizz,3); DEF(Buzz,5); template<int c,int fiz,int buz> struct FizzBuzz { static void exec() { (Fizz<fiz>::out() + Buzz<buz>::out()) || cout << c; FizzBuzz<c+1,Fizz<fiz>::next,Buzz<buz>::next>::exec(); } }; template<int fiz,int buz> struct FizzBuzz<101,fiz,buz> {static void exec(){}}; int main() { FizzBuzz<1,1,1>::exec(); cout << endl; }
で、名前とか超最適化
#include <iostream> using std::cout; #define S static #define T template #define D(i,a,b)T<int n>struct i{S bool o(){if(n==b)cout<<#a;return n==b;}S const int x=(n-b)?n+1:1;} D(y,Fizz,3); D(z,Buzz,5); T<int c,int f,int b> struct s { S void e(){ y<f>::o()+z<b>::o()||cout<<c; s<c+1,y<f>::x,z<b>::x>::e(); } }; T<> struct s<101,2,1> {S void e(){}}; int main(){ s<1,1,1>::e(); }
インデントとマクロ末尾以外の改行を除去して361バイト。
うむむこんなものか。