の続きです。コンパイル時にズンドコキヨシをやってみました。 static_assert
で、ちゃんとシーケンスの最後の5つがズンズンズンズンドコになっているかを検証しています。Sprout.RandomとBoost.MPLを使用しています。参考にした記事は以下になります。Sprout.Randomの使い方と、call_nを参考にしました。
Sprout.Random - コンパイル時の乱数生成 - ボレロ村上 - ENiyGmaA Code
http://d.hatena.ne.jp/osyo-manga/20130413/1365860245
The MPL Reference Manual - 1.60.0
#include <iostream> #include <type_traits> #include <boost/mpl/advance.hpp> #include <boost/mpl/begin_end.hpp> #include <boost/mpl/equal.hpp> #include <boost/mpl/for_each.hpp> #include <boost/mpl/iterator_range.hpp> #include <boost/mpl/push_back.hpp> #include <boost/mpl/size.hpp> #include <boost/mpl/vector.hpp> #include <sprout/random.hpp> namespace mpl = boost::mpl; constexpr std::size_t seed = SPROUT_UNIQUE_SEED; constexpr auto engine = sprout::random::minstd_rand0(seed); constexpr auto dist = sprout::random::uniform_smallint<int>(0, 1); template <typename Gen> constexpr int call_n(Gen&& gen, int index) { return index <= 0 ? *gen : call_n(gen(), index - 1); } struct Zun { static constexpr char const* value = "ズン"; }; struct Doko { static constexpr char const* value = "ドコ"; }; template <typename Seq, int N> struct push_back_zundoko; template <typename Seq> struct push_back_zundoko<Seq, 0> { using type = typename mpl::push_back<Seq, Zun>::type; }; template <typename Seq> struct push_back_zundoko<Seq, 1> { using type = typename mpl::push_back<Seq, Doko>::type; }; template <typename Seq, bool EnoughSize> struct is_zundoko_impl { using first = typename mpl::advance_c<typename mpl::end<Seq>::type, -5>::type; using last = typename mpl::end<Seq>::type; using range = mpl::iterator_range<first, last>; using type = typename mpl::equal<range, mpl::vector<Zun, Zun, Zun, Zun, Doko>>::type; }; template <typename Seq> struct is_zundoko_impl<Seq, false> { using type = mpl::false_; }; template <typename Seq> struct is_zundoko { using type = typename is_zundoko_impl<Seq, mpl::size<Seq>::type::value >= 5>::type; }; template <typename Seq, int N, typename Completion> struct zundoko_impl { using next_seq = typename push_back_zundoko<Seq, call_n(dist(engine), N)>::type; using completion = typename is_zundoko<next_seq>::type; using type = typename zundoko_impl<next_seq, N + 1, completion>::type; }; template <typename Seq, int N> struct zundoko_impl<Seq, N, mpl::true_> { using type = Seq; }; struct zundoko { using type = zundoko_impl<mpl::vector<>, 0, mpl::false_>::type; }; int main() { using zundoko_type = zundoko::type; static_assert(is_zundoko<zundoko_type>::type::value, ""); mpl::for_each<zundoko_type>([](auto const& item) { std::cout << std::remove_reference<decltype(item)>::type::value; }); std::cout << "キ・ヨ・シ!" << std::endl; }
実行結果例(コンパイル時に乱数列生成し終わっているので、コンパイルし直さない限り、何度やっても同じ結果になります)
clang++3.4以上,g++4.9.0以上で動作します。MSVCは14.0でもconstexprのサポートが弱いため動きません
追記
コードリファクタリングしました
#include <iostream> #include <boost/mpl/advance.hpp> #include <boost/mpl/begin_end.hpp> #include <boost/mpl/equal.hpp> #include <boost/mpl/eval_if.hpp> #include <boost/mpl/for_each.hpp> #include <boost/mpl/iterator_range.hpp> #include <boost/mpl/push_back.hpp> #include <boost/mpl/size.hpp> #include <boost/mpl/vector.hpp> #include <sprout/random.hpp> namespace mpl = boost::mpl; constexpr std::size_t seed = SPROUT_UNIQUE_SEED; constexpr auto engine = sprout::random::minstd_rand0(seed); constexpr auto dist = sprout::random::uniform_smallint<int>(0, 1); template <typename Gen> constexpr int call_n(Gen&& gen, int index) { return index <= 0 ? *gen : call_n(gen(), index - 1); } template <typename Seq> using end_t = typename mpl::end<Seq>::type; template <typename Iter, int N> using advance_c_t = typename mpl::advance_c<Iter, N>::type; template <typename Seq1, typename Seq2> using equal_t = typename mpl::equal<Seq1, Seq2>::type; struct zun { char const* value = "ズン"; }; struct doko { char const* value = "ドコ"; }; template <typename Seq, int N> struct push_back_zundoko : public mpl::eval_if_c<N == 0, mpl::push_back<Seq, zun>, mpl::push_back<Seq, doko> >::type {}; template <typename Seq, int N> using push_back_zundoko_t = typename push_back_zundoko<Seq, N>::type; template <typename Seq, bool EnoughSize, typename First> struct is_zundoko_impl : public equal_t< mpl::iterator_range<First, end_t<Seq>>, mpl::vector<zun, zun, zun, zun, doko> > {}; template <typename Seq, typename First> struct is_zundoko_impl<Seq, false, First> : public mpl::false_ {}; template <typename Seq> struct is_zundoko : public is_zundoko_impl<Seq, mpl::size<Seq>::type::value >= 5, advance_c_t<end_t<Seq>, -5> > {}; template <typename Seq> using is_zundoko_t = typename is_zundoko<Seq>::type; template <typename Seq, int N, typename Completion> struct zundoko_impl { private: using next_seq = push_back_zundoko_t<Seq, call_n(dist(engine), N)>; using completion = is_zundoko_t<next_seq>; public: using type = typename zundoko_impl<next_seq, N + 1, completion>::type; }; template <typename Seq, int N> struct zundoko_impl<Seq, N, mpl::true_> { using type = Seq; }; using zundoko = zundoko_impl<mpl::vector<>, 0, mpl::false_>::type; int main() { static_assert(is_zundoko<zundoko>::type::value, ""); mpl::for_each<zundoko>([](auto const& item) { std::cout << item.value; }); std::cout << "キ・ヨ・シ!" << std::endl; }