C++ で Boost.MPL を始めるなら知っておきたい10のこと
元ネタ:HerokuでWebアプリ開発を始めるなら知っておきたい10のこと
いいぜ、誰も書かないっていうなら、まず、俺が(ry。
と、そんな感じで、元ネタとの関係性は全くありませんが、『広めるためにはまず自分から……』って事で。
多分、誰も後に続かないだろうけども。
まぁ内容が適当なのでいつも通りです。
間違っててもいじめないでくだしあ><
ようこそ、コンパイルの世界へ。
1.BOOST_MPL_ASSERT
BOOST_STATIC_ASSERT(static_assert) の、Boost.MPL 版です。
内部で、"::value" を展開してくれます。
#include <boost/type_traits/is_same.hpp> #include <boost/mpl/assert.hpp> BOOST_MPL_ASSERT(( boost::is_same<int, int*> ));
[コンパイル出力]
no matching function for call to 'assertion_failed(mpl_::failed************ boost::is_same::************)'
他にも BOOST_MPL_ASSERT_NOT や、BOOST_MPL_ASSERT_MSG があります。
※マクロが 二重括弧(())になっていることに注意
2.Numeric
Boost.MPL では、値を型として扱います。
#include <boost/mpl/int.hpp> #include <boost/mpl/plus.hpp> #include <boost/mpl/not.hpp> #include <boost/mpl/or.hpp> #include <boost/mpl/bool.hpp> #include <boost/mpl/equal_to.hpp> namespace mpl = boost::mpl; typedef mpl::int_<3> _3; typedef mpl::int_<5> _5; BOOST_MPL_ASSERT(( mpl::equal_to< mpl::plus<_3, _5>, mpl::int_<8> > )); BOOST_MPL_ASSERT (( mpl::not_<mpl::bool_<false> > )); BOOST_MPL_ASSERT_NOT(( mpl::or_<mpl::false_, mpl::false_> ));
演算用のメタ関数があるので、四則演算も行う事が出来ます。
Boost.MPL では、"static const int value" ではなく、mpl::int_ が値として使用されます。
3.Sequence
Boost.MPL では、いくつかの Sequence が用意されています。
#include <boost/mpl/vector.hpp> #include <boost/mpl/list.hpp> #include <boost/mpl/equal.hpp> namespace mpl = boost::mpl; typedef mpl::vector<int, char, float> seq1; typedef mpl::vector<int, char, float> seq2; // mpl::equal は、Sequence の比較を行う BOOST_MPL_ASSERT(( mpl::equal< seq1, seq2 > ));
この様な形で定義、使用する事が出来ます。
4.Algorithm
Sequence を扱う為に、STL の様な Algorithm が用意されています。
#include <boost/mpl/vector.hpp> #include <boost/mpl/distance.hpp> #include <boost/mpl/count.hpp> #include <boost/mpl/equal_to.hpp> #include <boost/mpl/int.hpp> namespace mpl = boost::mpl; typedef mpl::vector<int, int, char, float> seq; // Sequence の begin と end を使用する typedef mpl::distance< mpl::begin<seq>::type, mpl::end<seq>::type > distance; BOOST_MPL_ASSERT(( mpl::equal_to<distance, mpl::int_<4> > )); // Sequence をそのまま使用する typedef mpl::count<seq, int> num; BOOST_MPL_ASSERT(( mpl::equal_to<num, mpl::int_<2> > ));
iterator を渡す必要があったり、Sequence を直接渡したりする細かい使用は、リファレンスを見てください。
5.Placeholders
Placeholders を使用して部分評価を行うことが出来ます。
#include <boost/type_traits/is_integral.hpp> #include <boost/mpl/vector.hpp> #include <boost/mpl/equal_to.hpp> #include <boost/mpl/int.hpp> #include <boost/mpl/count_if.hpp> #include <boost/mpl/placeholders.hpp> #include <boost/mpl/range_c.hpp> #include <boost/mpl/vector_c.hpp> typedef mpl::vector<int, int, char, float, short> seq; typedef mpl::count_if< seq, boost::is_integral<mpl::_1> > integral_num; BOOST_MPL_ASSERT(( mpl::equal_to<integral_num, mpl::int_<4> > )); // 定数 の Sequence で比較する場合は、 // mpl::equal_to<mpl::_1, mpl::_2> を使用しなければいけない BOOST_MPL_ASSERT(( mpl::equal< mpl::vector_c<int, 1, 2, 3>, mpl::range_c<int, 1, 4>, mpl::equal_to<mpl::_1, mpl::_2> > ));
count_if などに条件を指定する場合に、_1 を仮の型として渡すことで部分評価が行われます。
Boost.MPL では、template
6.Apply
Apply を 使用することで Placeholders で定義された型の評価を行います。
#include <boost/mpl/placeholders.hpp> #include <boost/mpl/apply.hpp> #include <boost/mpl/int.hpp> #include <boost/mpl/modulus.hpp> #include <boost/mpl/equal_to.hpp> namespace mpl = boost::mpl; // _1 % 2 == 0 typedef mpl::equal_to< mpl::modulus<mpl::_1, mpl::int_<2> >, mpl::int_<0> > is_even; BOOST_MPL_ASSERT(( mpl::apply<is_even, mpl::int_<4> >::type )); BOOST_MPL_ASSERT_NOT(( mpl::apply<is_even, mpl::int_<7> >::type ));
7.Lambda
Lambda を使用することで、Apply を介さずに Placeholders を評価することが出来ます。
#include <boost/mpl/lambda.hpp> #include <boost/mpl/placeholders.hpp> #include <boost/mpl/int.hpp> #include <boost/mpl/modulus.hpp> #include <boost/mpl/equal_to.hpp> namespace mpl = boost::mpl; typedef mpl::lambda< mpl::equal_to< mpl::modulus<mpl::_1, mpl::int_<2> >, mpl::int_<0> > >::type is_even_func; // ::apply を使用して、評価を行う BOOST_MPL_ASSERT(( is_even_func::apply<mpl::int_<4> > )); BOOST_MPL_ASSERT_NOT(( is_even_func::apply<mpl::int_<7> > ));
apply が内部関数として定義されているので、それを使用して評価を行います。
8.mpl::print
コンパイル時に型名を"警告"として出力してくれます。
#include <boost/mpl/int.hpp> #include <boost/mpl/modulus.hpp> #include <boost/mpl/equal_to.hpp> #include <boost/mpl/placeholders.hpp> #include <boost/mpl/lambda.hpp> #include <boost/mpl/print.hpp> namespace mpl = boost::mpl; typedef mpl::lambda< mpl::equal_to< mpl::modulus<mpl::_1, mpl::int_<2> >, mpl::int_<0> > >::type is_even_func; // print<>::type として定義することで出力が行われる typedef mpl::print< is_even_func::apply<mpl::int_<2> >::type >::type result;
[コンパイル時出力]
コンパイルされたクラスの テンプレート のインスタンス化 'boost::mpl::print' の参照を確認してください with [ T=boost::mpl::bool_ ] ::type を定義することで、type がコンパイル時に出力されます。 void を渡せなかったり、アンドキュメントだったり、typedef した型がうまく表示されなかったりとちょっと注意がいります。 9.mpl::string
コンパイル時に文字列を扱う事ができます。#include <boost/mpl/string.hpp> #include <iostream> typedef mpl::string<'hell', 'o wo', 'rld'> hello_world; int main(){ std::cout << mpl::c_str<hello_world>::value << std::endl; }[出力]hello world実行時の文字列のポインタは、mpl::c_str<>::value を使用して、取得することが出来ます。10.fizz_buzz
まとめとして、コンパイル時に fizz_buzz を行います。#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/string.hpp> #include <boost/mpl/for_each.hpp> #include <boost/mpl/range_c.hpp> #include <iostream> 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; typedef mpl::lambda< mpl::if_< is_fizz_buzz, mpl::c_str<mpl::string<'fizz', 'buzz'> >, mpl::if_< is_fizz, mpl::c_str<mpl::string<'fizz'> >, mpl::if_< is_buzz, mpl::c_str<mpl::string<'buzz'> >, mpl::_1 > > > >::type fizz_buzz; struct disp{ template<typename T> void operator ()(T) const{ std::cout << fizz_buzz::apply<T>::type::value << std::endl; } }; int main(){ mpl::for_each<mpl::range_c<int, 1, 20> >(disp()); }こんな感じで、コンパイル時に fizzbuzz を処理することが出来ます。 if_ とか、for_each とか、range_c とか、説明してないものも使用していますが、そこはがんばって自分で調べてください! そんな感じで、適当に書いてみました。 内容はあってないようなものですが、まぁ詳しくはリファレンスを参照してください。 とりあえず、 『俺はちゃんとを書いたんだから次はお前がやれよ!!』 的な感じで、早く誰か C++ とか、Boost とか、vim とかを書いてくだしあ。 他力本願ばんざーいい。 [boost] ver 1.46.1 [参照] http://www.boost.org/doc/libs/1_46_1/libs/mpl/doc/refmanual/refmanual_toc.html