boost fusion dynamic at_n
usage
boost::fusion::vector<int,double,std::string,char> vec(9 ,2.2 ,"aaa" ,'b'); std::cout << at_n_dynamic<double>(vec, 1) << std::endl; //=> 2.2
detail
#include <boost/fusion/include/vector.hpp> //#include <boost/fusion/algorithm.hpp> template<typename V> struct fusion_at_n_functor { mutable int i; int n; mutable V value; fusion_at_n_functor(int _n):i(0),n(_n){} void operator()(const V & t) const { if(i==n){value=t;} i++;} template<typename T> void operator()(const T & t) const { i++;} }; template <typename First,typename Last,typename AtN > void at_n_dynamic_fusion_impl(First i,Last last,AtN &atn,boost::mpl::true_ ){} template <typename First,typename Last,typename AtN > void at_n_dynamic_fusion_impl(First i,Last last,AtN &atn,boost::mpl::false_ ){ if(atn.i == atn.n ){atn(boost::fusion::deref(i));} else{ atn(boost::fusion::deref(i)); at_n_dynamic_fusion_impl(boost::fusion::next(i),last,atn, boost::fusion::result_of::equal_to< typename boost::fusion::result_of::next<First>::type,Last>());} } template <typename Ret,typename Sequence> Ret at_n_dynamic(Sequence & seq, int n){ fusion_at_n_functor<Ret> atn(n); #if 0 //debug boost::fusion::for_each(seq, atn); #else at_n_dynamic_fusion_impl(boost::fusion::begin(seq),boost::fusion::end(seq) ,atn, boost::fusion::result_of::equal_to< typename boost::fusion::result_of::begin<Sequence>::type, typename boost::fusion::result_of::end<Sequence>::type>()); #endif return atn.value;} /////////////////////////////////////////////// int main(){ boost::fusion::vector<int,double,std::string,char> vec(9 ,2.2 ,"aaa" ,'b'); std::cout << at_n_dynamic<double>(vec, 1) << std::endl; //=> 2.2 }
boost.variantの補助ツール
boost::variant に以下の動作をさせたい
variant<int,int> => int
variant<int,double> => double
variant<int , boost::rational<int> > => boost::rational<int>
variant<int , double , std::string> => variant<double,std::string>
しかしこうなってくれないので自分で拡張ツールを作った。
https://github.com/niitsuma/variant_shrink
(要するにdecltype(int+double)=>double みたいにまとめられる場合はまとめるけど、まとめられない場合はvariant
使用例
C++11が使えない環境でdecltypeの代用品として使う
template<typename X,typename Y> typename make_variant_shrink_over<boost::mpl::vector<X,Y> >::type //C++11ならdecltype(x+y)にできる adder(X x, Y y) {return x + y;} double r1= adder(1,1.1); boost::rational<int> x(2,3); boost::rational<int> r2 = adder(1,x);
使い方
boost::variant::make_variant_over<boost::mpl::vector<....> >::type
と同じ様に使う.
ファイル"variant_shrink.hpp"をインクルードするだけで使える
#include "variant_shrink.hpp" make_variant_shrink_over<boost::mpl::vector<int,int> >::type => int make_variant_shrink_over<boost::mpl::vector<int,boost::rational<int> >::type => boost::rational <int> make_variant_shrink_over<boost::mpl::vector<int,double > >::type => double make_variant_shrink_over<boost::mpl::vector<double,std::string> >::type => boost::variant<double,std::string> make_variant_shrink_over<boost::mpl::vector<double,int,std::string> >::type => boost::variant<double,std::string>
任意の縮小方法
デフォルトは
typedef boost::mpl::vector< int,boost::rational<int>,float,double,std::complex<double> >::type default_type_order;
となっていて
int < boost::rational<int> < float < double < std::complex<double>
の順番で型の一般化(縮約?)がされていく。この順番を変更したい場合は、一般化の順番を決める関数オブジェクトを2番めのテンプレート引数として入力する。例えば
bool < int < long < boost::rational<int> < boost::rational<long>
の順番で一般化したい場合は
typedef make_variant_shrink_over< boost::mpl::vector<float,bool,boost::rational<long> > , //2番めのテンプレート引数に順番情報を入力する generate_mpl_lambda_is_generalizable_to_from_type_order_sequence< boost::mpl::vector< bool , int , long , boost::rational<int> , boost::rational<long> //ここに自分の好きな順番を入れる > >::type >::type r8type; BOOST_MPL_ASSERT((boost::mpl::equal<r8type ,boost::variant<boost::rational<long> ,float> > ));
この2番めのテンプレート引数に入力する一般化の順番を決める関数オブジェクト
is_generalizable_to<TypeFrom,TypeTo>
は次のような意味を持つものを作ればよい
is_generalizable_to<float,double> => boost::mpl::true_ // float は double に一般化できる
is_generalizable_to<double,float> => boost::mpl::false_ //double は float に一般化できない
is_generalizable_to<std::string,float> => boost::mpl::false_ //std::string は floatと比較できない、またはfloatへの一般化はできない。
generate_mpl_lambda_is_generalizable_to_from_type_order_sequenceは一般化の順番ベクトル
generate_mpl_lambda_is_generalizable_to_from_type_order_sequence< boost::mpl::vector< bool , int , long , boost::rational<int> , boost::rational<long> > //一般化の順番ベクトル >
を入力すると、上記の反応をする関数オブジェクトを生成する。
もっと複雑な縮小順番も入力できる。
浮動小数型:
float < double < long double
整数型:
bool < char < short < int < long
の順番で縮約されて、なおかつ浮動小数と整数のunionはboost::variantにしたい場合はこうする。
template<typename T,typename TBase> struct is_generalizable_to_custom : public boost::mpl::if_< boost::is_floating_point<T> , typename boost::mpl::if_< boost::is_floating_point<TBase> ,is_less_in_orderd_mpl_sequence< T,TBase,boost::mpl::vector<float,double,long double > > //浮動小数型の順番 ,boost::mpl::false_ //浮動小数型と整数型のUnionはそのままvarinatにする >::type ,typename boost::mpl::if_< boost::is_integral<T> ,typename boost::mpl::if_< boost::is_integral<TBase> ,is_less_in_orderd_mpl_sequence< T,TBase,boost::mpl::vector<bool,char,short,int,long> > //整数型の順番 ,boost::mpl::false_ >::type ,boost::mpl::false_ //他の型(std::stringとか)はそのままにする >::type >::type {}; typedef boost::mpl::lambda<is_generalizable_to_custom< boost::mpl::_1 , boost::mpl::_2 > >::type is_generalizable_to_custom_mpl_lambda; //boost::mpl::lambdaで包まないと関数オブジェクトとして引数に渡せない typedef make_variant_shrink_over< boost::mpl::vector<double,float,bool,char> ,is_generalizable_to_custom_mpl_lambda //2つ目のtemplate引数として上記で生成した関数オブジェクトを入力 >::type r10type; BOOST_MPL_ASSERT((boost::mpl::equal<r10type ,boost::variant<double,char> >));
ここで使った補助関数
is_less_in_orderd_mpl_sequence<T1, T2,OrderVector>
は
is_less_in_orderd_mpl_sequence<int, double ,mpl::vector<bool,int,double,long double> > => mpl::true_ is_less_in_orderd_mpl_sequence<double, int ,mpl::vector<bool,int,double,long double> > => mpl::false_
のようなT1がT2よりも先に順番ベクトルに出現する時にtrue_となる関数オブジェクト
関連
- http://cpplover.blogspot.jp/2013/03/commontypedecay.html
- http://en.cppreference.com/w/cpp/types/common_type
- Boost.Fusion から Boost.Variant を定義 http://d.hatena.ne.jp/osyo-manga/20111129/1322578311
- FusionシーケンスをMPLシーケンスとして扱う http://d.hatena.ne.jp/faith_and_brave/20110113/1294894695
- http://www.kmonos.net/alang/boost/classes/variant.html
- http://stackoverflow.com/questions/6773997/using-mplvector-to-define-boostvariant-types
- http://stackoverflow.com/questions/13750838/how-to-implement-a-boostvariant-derived-class
- http://boost.2283326.n4.nabble.com/boost-users-Variant-Sequence-instantiation-td2595983.html
boost coroutine
boost context
- Boost.Context について調べた http://d.hatena.ne.jp/melpon/20111213/1323704464
- Continuation with Boost.Context http://www.slideshare.net/faithandbrave/continuation-with-boostcontext
boost coroutine
- http://www.boost.org/doc/libs/1_55_0/libs/coroutine/doc/html/index.html
- http://www.slideshare.net/melpon/boostcoroutine-10127544
- http://d.hatena.ne.jp/joynote/20131118/1384779314
- http://flast.hateblo.jp/entry/2013/10/05/181134
- http://seiya-kumada.blogspot.jp/2013/08/c-boostcoroutine.html
- Coroutines in C++ http://aldrin.co/coroutine-basics.html
example
- http://mattn.kaoriya.net/software/lang/c/20130213164417.htm
- buildで苦労するみたいだ
scm2cpp
scm2cpp is READABLE C++ code generator from Scheme code.
Ver 0.6
- URL http://www.suri.cs.okayama-u.ac.jp/servlets/APPLICATION.rkt
- simple expantion scm2c http://people.csail.mit.edu/jaffer/Schlep/scm2c.html
- need C++11
- Not support
- define inside define ...
- Bug
- many bugs related to let
Ver 0.7
- URL http://www.suri.cs.okayama-u.ac.jp/servlets2/scm2cpp.rkt
- Feature
- Support
- uniform vector, uniform list ...
- More statement can deal than Ver 0.6
- Not support
- call/cc , string , char , symbol, switch , car , cdr , cons , let* , letrec , hash , alist ...
- no difference let let*
- tail recursion does not expanded
- some type declaration does not work than Ver0.6
- Bug in 0.7.2
- function should not return lambda
- function should not return do block
- related work http://www-ti.informatik.uni-tuebingen.de/~weissr/doc/scm2cpp.pdf
- Require C++ library
- Boost.Array Boost.Assign Boost.Fusion Boost.Function
- In ver 0.7.2 following implemented, but not tested.
- do , named let , cond
scm2cpp usage
- Download and Unpack http://www.suri.cs.okayama-u.ac.jp/~niitsuma/scm2cpp/scm2cpp-0.7-commandline.tar.gz
- cd scm2cpp-0.7-commandline
- racket scm2cpp.scm -t scm2c.typ sample.scm
- g++ sample.cpp
- more example
see file scm2cpp-0.7-commandline/benchmark/makefile
scm2cpp benchmark
fft.scm
http://www.suri.cs.okayama-u.ac.jp/~niitsuma/scm2cpp/benchmark/fft.scm
system | stalin | scm2cpp | scm2cpp +openmp | scm2cpp +manual rewrite | gambit-c | chicken | racket | gauche |
i7@2.93GHz ubuntu | 0.231 sec | 0.407 sec | 0.092 sec | 0.230 sec | 7.408 sec | 18.236 sec | 6.624 sec | 38.055 sec |
MacBook core2duo 2.26Ghz | - | 0.984 | - | - | 16.797 | - | - | - |
MacBook
- Gambit-C
$ time ./fft-gambit real 0m16.797s user 0m13.046s sys 0m0.135s
- scm2cpp
$ time ./fft.exe real 0m5.202s user 0m4.298s sys 0m0.029s
- scm2cpp with g++ O3
$ time ./fft-O3 real 0m0.984s user 0m0.807s sys 0m0.005s
Environment
MacBook core2duo 2.26Ghz
$ uname -a
Darwin 10.8.0 Darwin Kernel Version 10.8.0: Tue Jun 7 16:33:36 PDT 2011; RELEASE_I386 i386
stream-cons & stream-cdr using boost.proto & boost.fusion
#include <boost/fusion/container/vector.hpp> #include <boost/fusion/algorithm.hpp> #include <boost/fusion/sequence.hpp> #include <boost/fusion/include/vector.hpp> #include <boost/fusion/container/list/cons.hpp> #include <boost/fusion/include/cons.hpp> #include <boost/proto/proto.hpp> template<typename T> typename boost::proto::result_of::eval<T,boost::proto::default_context >::type proto_force(T t){ return boost::proto::eval(t,boost::proto::default_context()); } template<typename T> typename boost::proto::result_of::eval< typename T::cdr_type::car_type, boost::proto::default_context >::type stream_cdr(T t) { return proto_force((t.cdr).car);} template<typename T1,typename T2> typename boost::fusion::cons<T1, boost::fusion::cons< typename boost::proto::terminal<T2>::type >> stream_cons(T1 t1 ,T2 t2) { boost::proto::terminal<T2>::type td2={t2}; boost::fusion::cons< boost::proto::terminal<T2>::type > tc2(td2); boost::fusion::cons<T1, boost::fusion::cons< boost::proto::terminal<T2>::type >> tt(t1,tc2); return tt; } int main() { auto s= stream_cons(2,stream_cons(1,0)); auto ss= stream_cons(3, s); std::cout << proto_force(s.cdr.car).car << std::endl; //ok std::cout << proto_force(proto_force(s.cdr.car).cdr.car) << std::endl; //ok std::cout << s.car << std::endl;//ok std::cout << stream_cdr(s).car << std::endl; //ok std::cout << stream_cdr(ss).car << std::endl; //ok std::cout << proto_force(ss.cdr.car).car << std::endl; //ok std::cout << proto_force( proto_force(ss.cdr.car).cdr.car).car << std::endl; //not work why? std::cout << stream_cdr(stream_cdr(ss)).car << std::endl; //not work why? }