自作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^)\ナンテコッタイ