コンパイル時 FizzBuzz を読んでの Sprout C++ Library 改善
id:osyo-manga さんの Sprout を使った記事↓
[C++][Sprout]Sprout でコンパイル時 FizzBuzz
http://d.hatena.ne.jp/osyo-manga/20111207/1323187352
を読んで、「ああ、Sprout にこんな機能が足りなかったな」という部分に思い当たったので、
それを追加した上で件のコードを勝手に書き直してみました。
なお、元コードのロジック自体には手を入れていません。
#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 <sprout/numeric/iota.hpp> #include <sprout/pit.hpp> #include <iostream> // → sprout::make_string を使う template<typename T, typename Result = sprout::string<15> > constexpr Result itoa_impl(T n){ return n <= 10 ? sprout::make_string(char('0' + n)) : sprout::realign_to<Result>(itoa_impl(n/10) + sprout::make_string(char('0' + n%10))); } template<typename T, typename Result = sprout::string<16> > constexpr Result itoa(T n){ return n < 0 ? ("-" + itoa_impl(-n)) : itoa_impl(n); } struct fizzbuzz{ typedef sprout::string<8> result_type; constexpr result_type operator ()(int n) const{ return n % 15 == 0 ? sprout::to_string("FizzBuzz") : n % 3 == 0 ? sprout::to_string("Fizz") : n % 5 == 0 ? 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", ""); // 値を定義、[1..15] // → sprout::iota を使う constexpr auto source = sprout::iota( sprout::pit<sprout::array<int, 15> >(), 1 ); // 値から FizzBuzz の出力へ変換 // → 空のテンポラリの代わりに sprout::pit を使う constexpr auto result = sprout::transform( source.begin(), source.end(), sprout::pit<sprout::array<string, 15> >(), fizzbuzz() ); // コンパイル時に計算結果を確認 // → string の暗黙の変換が使える constexpr auto fizzbuzz_result = sprout::make_array<string>( sprout::to_string("1"), sprout::to_string("2"), sprout::to_string("Fizz"), sprout::to_string("4"), sprout::to_string("Buzz"), sprout::to_string("Fizz"), sprout::to_string("7"), sprout::to_string("8"), sprout::to_string("Fizz"), sprout::to_string("Buzz"), sprout::to_string("11"), sprout::to_string("Fizz"), sprout::to_string("13"), sprout::to_string("14"), sprout::to_string("FizzBuzz") ); static_assert(result == fizzbuzz_result, ""); // 実行時に出力 for(auto&& str : result){ std::cout << str << ", "; } std::cout << std::endl; return 0; }
まず追加したのは、sprout::make_string です。
これは、文字型のパラメータパックから文字列を構築する関数です。
static_assert(sprout::make_string('f', 'o', 'o', 'b', 'a', 'r') == "foobar", "");
次に、sprout::basic_string の暗黙の変換です。
string
string<10> str = sprout::to_string("foobar");
また、これは以前からあったものですが sprout::iota が使えます。
#include <sprout/numeric/iota.hpp>
sprout::iota(c, v) は、コンテナ c の要素を v, v+1, v+2,... で充填します。
Sprout のアルゴリズムを使う際、テンポラリ変数が必要になるケースでは sprout::pit が使えます。
#include <sprout/pit.hpp>
sprout::pit
Container がそのアルゴリズムの結果型になるという性質を持ちます。
これを使うことでテンポラリ変数の使用を回避できます。