自作lambda 作って失敗した。
0xではないふつーのC++で独自実装によるラムダ式をつくってみようかなーって思っていろいろ実験していた。
結局うまくいかなかったけど、試行錯誤した記録を書いとく。
なんで boost のlambda があんなふうな複雑な文法になったのかわか気がした。
まず自作lambdaの文法を考えてみる。
やっぱ簡単に定義したいし、capture とかもやりたいなぁ。
MY_LAMBDA_BEGIN1(int,int) { return _1 + 12; } MY_LAMBDA2(capture...)
で、自由な構文を書くためには、 関数内class を取るしかない。
nazonazo() { struct InnerClass { int lambda(int _1) { return _1 + 12; } }; }
で、lambda なんだから、 lambda(1); とかで実行したい。
それには、operator () を利用する。
nazonazo() { struct InnerClass { int lambda(int _1) { return _1 + 12; } int operator ()(int _1) { return this->lambda(_1); } }; InnerClass a; a(1); //ok }
lambdaなんだから、 return で関数を返したい。
これは、継承とかをごにょって あげればできるる
struct Super { virtual operator ()(int _1) = 0; }; Super* nazonazo() { struct InnerClass : public Super { int lambda(int _1) { return _1 + 12; } int operator ()(int _1) { return this->lambda(_1); } }; //InnerClass a; //これはダメ。 //return &a; //ローカル変数の参照を返すとかマジキチ。 static InnerClass a; //動くけどスレッドセーフではないよね return &a; }
スレッドセーフにするためと、 static でずっとメモリが取られるのは嫌なのでなんとかする。
auto_ptr<> とかで逃げてみる。
struct Super { virtual operator ()(int _1) = 0; }; auto_ptr<Super> nazonazo() { struct InnerClass : public Super { int lambda(int _1) { return _1 + 12; } int operator ()(int _1) { return this->lambda(_1); } }; return auto_ptr<Super>( new InnerClass); }
これでOK。
しかし、利用する方がちょっとまずい。
今度は、 nazonazo() を受け取る方を考えてみる。
void main() { auto_ptr<Super> func = nazonazo(); (*func)(1); //OK しかしダサい。 //func(1) と呼び出したいよね!! }
(*func)(1); とか、まともな神経をしていたら、こんなの絶対おかしいよ!!ってしゃうとするところだと思う。
なんで、これを何とかして、 func(1)と呼び出せるようにしてみる。
auto_ptr を継承すればいいんじゃなイカ?
しかし、なんかこれがうまくいかんかった。
struct Super { virtual operator ()(int _1) = 0; }; remplate<classname _T> struct my_auto_ptr : public _auto_ptr<_T> { int operator ()(int _1) { return this->Ref->()(_1); } }; my_auto_ptr<Super> nazonazo() { struct InnerClass : public Super { int lambda(int _1) { return _1 + 12; } int operator ()(int _1) { return this->lambda(_1); } }; return my_auto_ptr<Super>( new InnerClass); }
仕方ないので、 自作 auto_ptr を作ってみた。
#たぶん、何か穴があると思うが細かいことは気にしない方向で。
template<typename _T> struct my_auto_ptr { _T* MyRef; _T* Ref; my_auto_ptr() { this->MyRef = NULL; this->Ref = NULL; } my_auto_ptr(_T* ref) { this->MyRef = ref; this->Ref = ref; } virtual ~my_auto_ptr() { delete Ref; } my_auto_ptr(const my_auto_ptr& obj) { if (this->Ref != obj.Ref){ delete this->Ref; } this->MyRef = obj.MyRef; this->Ref = NULL; } int operator()(int a1){ return this->MyRef->operator()(a1); } } struct Super { virtual operator ()(int _1) = 0; }; my_auto_ptr<Super> nazonazo() { struct InnerClass : public Super { int lambda(int _1) { return _1 + 12; } int operator ()(int _1) { return this->lambda(_1); } }; return my_auto_ptr<Super>( new InnerClass); } void main() { auto_ptr<Super> func = nazonazo(); func(1); //OK! }
やったー。うまくできた。
あとは、これを template で包んで揚げて、汎用化すればOK!だね!!!
最終的には、 こんな風に書きたいね!
my_auto_ptr<Super> nazonazo() { return LAMBDA_BEGIN() { return _1 + 1; } LAMBDA_END(); }
しかし!!
これではだめなのだ。
このラムダの実装だと、それができないのだ。
my_auto_ptr<Super> nazonazo() { return LAMBDA_BEGIN() { return _1 + 1; } LAMBDA_END(); } ↓↓↓↓↓↓↓↓↓↓↓↓↓ //こんな文法あるわけない!! my_auto_ptr<Super> nazonazo() { return struct InnerClass : public Super { int lambda(int _1) { return _1 + 12; } int operator ()(int _1) { return this->lambda(_1); } } ,my_auto_ptr<Super>( new InnerClass) } ↓↓↓↓↓↓↓↓↓↓↓↓↓ //どうやっても定義とreturn文は別だ! Super nazonazo() { return struct : public Super { int lambda(int _1) { return _1 + 12; } int operator ()(int _1) { return this->lambda(_1); } } InnerClass(); }
つまり、 struct は定義であり、値を返すわけではない。
return は文だから、 値を返す必要がある。
そんなわけで、どうしても、2行にならないといけない。
それで何が困るか?
→アルゴリズムに簡単に渡せなくなる。
sort(begin() , end() , LAMBDA ) ってやりたいぢゃん。
だけど、この実装だと、2行になってしまう。
LAMBDA myfunc; sort(begin() , end() , myfunc );
あーだめだ。オワタ。/(^o^)\ナンテコッタイ