Sprout でコンパイル時 FizzBuzz

って事でやってみました。
counting_iterator が欲しくなりますね。

[ソース]

#define SPROUT_CONFIG_SUPPORT_TEMPORARY_CONTAINER_ITERATION
#include <sprout/algorithm/transform.hpp>
#include <sprout/array.hpp>
#include <sprout/string.hpp>
#include <sprout/string/alias.hpp>
#include <sprout/operation.hpp>
#include <iostream>


template<typename Char>
constexpr sprout::basic_string<Char, 1>
to_string(Char c){
    return sprout::push_front(sprout::to_string(""), c);
}


template<typename T, typename Result = sprout::string<16> >
constexpr Result
itoa_impl(T n){
    return n <= 10 ? sprout::realign_to<Result>(::to_string(char('0' + n)))
         : sprout::realign_to<Result>(itoa_impl(n/10) + ::to_string(char('0' + n%10)));
}

template<typename T, typename Result = sprout::string<16>>
constexpr Result
itoa(T n){
    return n < 0 ? sprout::realign_to<Result>(("-" + itoa_impl(-n)))
         : sprout::realign_to<Result>(itoa_impl(n));
}


struct fizzbuzz{
    typedef sprout::string<8> result_type;

    constexpr result_type
    operator ()(int n) const{
        return n % 15 == 0 ? sprout::realign_to<result_type>(sprout::to_string("FizzBuzz"))
             : n %  3 == 0 ? sprout::realign_to<result_type>(sprout::to_string("Fizz"))
             : n %  5 == 0 ? sprout::realign_to<result_type>(sprout::to_string("Buzz"))
             : sprout::realign_to<result_type>(itoa(n));
    }
};



int
main(){
    typedef fizzbuzz::result_type string;

    // 関数のテスト
    static_assert(fizzbuzz(1) == "1", "");
    static_assert(fizzbuzz(2) == "2", "");
    static_assert(fizzbuzz(3) == "Fizz", "");
    static_assert(fizzbuzz(5) == "Buzz", "");
    static_assert(fizzbuzz(15) == "FizzBuzz", "");

    // 値を定義、ちとださい
    constexpr auto source = sprout::make_common_array(
        1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
    );
    
    // 値から FizzBuzz の出力へ変換
    constexpr sprout::array<string, 15> tmp{};
    constexpr auto result = sprout::transform(source.begin(), source.end(), tmp, fizzbuzz());
    
    // コンパイル時に計算結果を確認
    constexpr auto fizzbuzz_result = sprout::make_common_array(
        sprout::realign_to<string>(sprout::to_string("1")),
        sprout::realign_to<string>(sprout::to_string("2")),
        sprout::realign_to<string>(sprout::to_string("Fizz")),
        sprout::realign_to<string>(sprout::to_string("4")),
        sprout::realign_to<string>(sprout::to_string("Buzz")),
        sprout::realign_to<string>(sprout::to_string("Fizz")),
        sprout::realign_to<string>(sprout::to_string("7")),
        sprout::realign_to<string>(sprout::to_string("8")),
        sprout::realign_to<string>(sprout::to_string("Fizz")),
        sprout::realign_to<string>(sprout::to_string("Buzz")),
        sprout::realign_to<string>(sprout::to_string("11")),
        sprout::realign_to<string>(sprout::to_string("Fizz")),
        sprout::realign_to<string>(sprout::to_string("13")),
        sprout::realign_to<string>(sprout::to_string("14")),
        sprout::realign_to<string>(sprout::to_string("FizzBuzz"))
    );
    static_assert(result == fizzbuzz_result, "");

    // 実行時に出力
    for(auto&& str : result){
        std::cout << str << ", "
    }
    
    return 0;
}

[出力]

1, 2, Fizz, 4, Buzz, Fizz, 7, 8, Fizz, Buzz, 11, Fizz, 13, 14, FizzBuzz, 

sprout::transform を使用して、値から FizzBuzz の結果へ変換しています。
sprout::basic_string を別のサイズの basic_string へキャストするには、sprout::realign_to を使用します。
これで、FizzBuzz も戻り値型を同じ型へと変換しています。
演算子がある程度使えるのでコンパイル時チェックも楽ですねー。

[コンパイラ]

  • g++ (GCC) 4.7.0 20111112 (experimental)