FizzBuzzを書こう!

FizzBuzzプログラム

時間が時間なので出来たものだけペタリ
http://ideone.com/GYAGs
また時間ある時に覚えてたら(←)また解説書きます。追記:書きました(10/06/20)
・・・ptr

解説

ソース

とりあえずソースをこっちにも貼っておきます。

#include <iostream>
#include <boost/function.hpp>
#include <boost/lambda/lambda.hpp>
#include <boost/lambda/if.hpp>
#include <boost/lambda/bind.hpp>
using namespace std;
using namespace boost::lambda;

int main( void )
{
	boost::function<void(int)> func = (if_(_1<=100)[if_(_1%3&&_1%5)[cout<<_1],if_(!(_1%3))[cout<<constant("Fizz")],if_(!(_1%5))[cout<<constant("Buzz")],cout<<constant('\n'),bind(constant_ref(func),_1+1)]);
	func(1);
}

見ての通りBoostを使用しております。
「Boostとはなんぞ?」と言う方はBoostでググッてください(丸投げ)。
簡単に説明するとC++の便利なライブラリ群です。

boost::lambda

このソースの肝はboost::lambdaです。
boost::lambdaはC++ラムダ式が書けるようになるライブラリです。
このboost::lambdaは内部でゴニョゴニョしてラムダ式全体をなんとかして関数オブジェクト化してしまうことによって実現しています。
ということで、

(if_(_1<=100)[if_(_1%3&&_1%5)[cout<<_1],if_(!(_1%3))[cout<<constant("Fizz")],if_(!(_1%5))[cout<<constant("Buzz")],cout<<constant('\n'),bind(constant_ref(func),_1+1)])

これ全体がひとつの関数オブジェクトです。
途中で出てくる_1はプレースホルダなので、普通の関数でいう引数です。
そして、boost::lambdaでのラムダ式中でifを使うときはifの代わりにif_を使います。
またその後に続くブロックは{}ではなく[]を使います。
さらに、処理を複数書きたい場合は;ではなく,を使います。
こうやって言われると大体どうやって実現してるか少しわかりますねw
さらに、cout << で最初に来るものがラムダ式以外のものであると問題が起こります。
これの詳細は省略しますが、これに対処するためにconstantを使ってラムダ式化します。
最後にラムダ式内で関数を呼び出すときは普通に書くのではなくboost::lambda::bindを使います。
ちなみにboost::bindの機能すべてを含んでいるらしいです。
これの第一引数には呼び出す関数を指定するのですが、今回は外部の変数であるためconstant_refを用いてラムダ式中で使えるようにします。
この呼び出す関数はその後の代入で分かる通りラムダ式自身です。
これで再帰を実現します。


ということで、これを普通の(テンプレート)関数に直すとこんな感じです。

template<class T>
void unnamed_func( T i )
{
	if( i <= 100 ) {
		if( i % 3 && i % 5 )
			cout << i;

		if( ! ( i % 3 ) )
			cout << "Fizz";

		if( ! ( i % 5 ) )
			cout << "Buzz";

		cout << '\n';

		unnamed_func( i + 1 );
	}
}

おわり

なんの説明にもなってないですね、はい。
自分自身がBoostを理解してないのが一番の問題・・・><;
あと、出来ればfuncという変数は作りたくなかった><;;;