コンパイル時 FizzBuzz

なんか Twitter で話題になっていたので、Boost.MPL を使った FizzBuzz でも。
mpl::print を使用して、コンパイル時に出力も行います。

[ソース]

#include <boost/mpl/int.hpp>
#include <boost/mpl/modulus.hpp>
#include <boost/mpl/equal_to.hpp>
#include <boost/mpl/and.hpp>
#include <boost/mpl/if.hpp>
#include <boost/mpl/transform.hpp>
#include <boost/mpl/print.hpp>
#include <boost/mpl/vector_c.hpp>

namespace mpl = boost::mpl;

typedef mpl::equal_to<
    mpl::modulus<mpl::_1, mpl::int_<3> >,
    mpl::int_<0>
> is_fizz;

typedef mpl::equal_to<
    mpl::modulus<mpl::_1, mpl::int_<5> >,
    mpl::int_<0>
> is_buzz;

typedef mpl::and_<is_fizz, is_buzz> is_fizz_buzz;

struct Fizz;
struct Buzz;
struct FizzBuzz;

typedef mpl::lambda<
    mpl::if_<
        is_fizz_buzz,
        FizzBuzz,
        mpl::if_<
            is_fizz,
            Fizz,
            mpl::if_<
                is_buzz,
                Buzz,
                mpl::_1
            >
        >
    >
>::type fizz_buzz;

typedef mpl::transform<
    mpl::vector_c<int,
        1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
        11, 12, 13, 14, 15, 16, 17, 18, 19, 20
    >,
    fizz_buzz
> result;

typedef mpl::print<result::type>::type disp;

int main(){}

[出力]

|| main.cpp
\boost\boost_1_47_0\boost\mpl\print.hpp|51 warning 4308| 負の整数定数が符号なしの型に変換されました。
main.cpp|56| コンパイルされたクラスの テンプレート のインスタンス化 'boost::mpl::print<T>' の参照を確認してください
||         with
||         [
||             T=boost::mpl::vector20<boost::mpl::integral_c<int,1>,boost::mpl::integral_c<int,2>,Fizz,boost::mpl::integral_c<int,4>,Buzz,Fizz,boost::mpl::integral_c<int,7>,boost::mpl::integral_c<int,8>,Fizz,Buzz,boost::mpl::integral_c<int,11>,Fizz,boost::mpl::integral_c<int,13>,boost::mpl::integral_c<int,14>,FizzBuzz,boost::mpl::integral_c<int,16>,boost::mpl::integral_c<int,17>,Fizz,boost::mpl::integral_c<int,19>,Buzz>
||         ]

コンパイル時の出力は msvc が一番綺麗に出力されると思います。
C++03 でも動きます。

[おまけ]

普通に書いてみたらこんな感じになった。

[ソース]

#include <iostream>
#include <string>
#include <boost/variant.hpp>
#include <boost/range/irange.hpp>
#include <boost/range/adaptor/transformed.hpp>
#include <boost/range/algorithm/for_each.hpp>
#include <boost/lambda/lambda.hpp>
#include <boost/lexical_cast.hpp>

struct to_fizzbuzz{
    typedef std::string result_type;

    template<typename T>
    result_type
    operator ()(T n) const{
        return n % 15 == 0 ? "FizzBuzz"
             : n %  3 == 0 ? "Fizz"
             : n %  5 == 0 ? "Buzz"
             : boost::lexical_cast<std::string>(n);
    }
};

int
main(){
    using boost::adaptors::transformed;
    using boost::lambda::_1;
    int size = 100;

    boost::for_each(
        boost::irange(1, size)|transformed(to_fizzbuzz()),
        std::cout << _1 << ","
    );
    return 0;
}

うーむ、面白みが不足している。