C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[13]: delegateをboost::lambdaでやってみたい


(過去ログ 21 を表示中)

[トピック内 14 記事 (1 - 14 表示)]  << 0 >>

■8792 / inTopicNo.1)  delegateをboost::lambdaでやってみたい
  
□投稿者/ デフォルトの名無し (1回)-(2007/10/10(Wed) 14:26:44)

分類:[C/C++] 

C#の無名関数の勉強ついでに、/*今更感が否めないのですが*/C++のboooooooooostに興味津々なので、やってみました。
んで、いきなりコケました。
何がいかんのか、教えてください。
あ、とくに意味のあるコードじゃないです。適当です、適当。

・C#のコード
 class Program
 {
  delegate int Method(int n);

  static void Main(string[] args)
  {
   Method func0 = delegate(int n) { return n; };
   Method func1 = delegate(int n) { return func0(2 * n); };
  }
 }

・翻訳してみたC++のコード
 #include <boost/bind.hpp>
 #include <boost/function.hpp>
 #include <boost/lambda/lambda.hpp>
 int main()
 {
  typedef boost::function<int(int)> Method;
  Method func0 = (boost::lambda::_1);
  Method func1 = boost::bind(func0, 2 * boost::lambda::_1);
  return 0;
 }

コンパイルエラーになりまして、エラーに飛ぶと、boost::bindのコードに行ってしまいます。
悪いのはたぶんfunc1の行だと思うんですけど。
VisualStudio 2005でやってます。

なしてー?どぼちてー?
ものすごーく基本的なミスの悪寒。
引用返信 編集キー/
■8813 / inTopicNo.2)  Re[1]: delegateをboost::lambdaでやってみたい
□投稿者/ ぽぴ王子 (272回)-(2007/10/10(Wed) 22:44:47)
くだらないこと聞かないでね。
引用返信 編集キー/
■8814 / inTopicNo.3)  Re[2]: delegateをboost::lambdaでやってみたい
□投稿者/ デフォルトの名無し (2回)-(2007/10/10(Wed) 22:49:11)
> くだらないこと聞かないでね。

くだらなくてすみませんでした。
ごめんなさい。
解決済み
引用返信 編集キー/
■8818 / inTopicNo.4)  Re[3]: delegateをboost::lambdaでやってみたい
□投稿者/ 中博俊@管理人 (2回)-(2007/10/10(Wed) 23:49:16)
中博俊@管理人 さんの Web サイト
このコメントは偽物です。
デフォルトさん惑わされないでください。
引用返信 編集キー/
■8820 / inTopicNo.5)  Re[4]: delegateをboost::lambdaでやってみたい
□投稿者/ 囚人 (200回)-(2007/10/11(Thu) 00:11:43)
boost::bind(func0, 2 * boost::lambda::_1);
だと、func0 の引数に関数オブジェクトを渡すみたいになりません?
また、bind の _1 と boost::lambda の _1 は別物ですけど、それは認識されてますか?

Method func1 = boost::bind(func0, _1 * 2);
が正しそうだけど、無理ですねぇ。

Method func1 = boost::bind(func0, _1);
が限界なんでしょうか。

引用返信 編集キー/
■8821 / inTopicNo.6)  Re[5]: delegateをboost::lambdaでやってみたい
□投稿者/ ぽぴ王子 (273回)-(2007/10/11(Thu) 00:23:54)
ぽぴ王子 さんの Web サイト
えっと、本物が来ました。
名前を書くだけだから、誰でも偽物になれるんですねえ。

くだらないこととは思いませんでしたよ。少なくとも本物の人は。
まぁ文章を見て「2chでやれ」とか思ったことは思いましたが、研究することは悪いことじゃないですし。

肝心の内容については、C++ はほとんどやってないので答えられないです。
ごめんなさい。

引用返信 編集キー/
■8826 / inTopicNo.7)  Re[6]: delegateをboost::lambdaでやってみたい
□投稿者/ デフォルトの名無し (3回)-(2007/10/11(Thu) 01:15:48)
ちょっとヘコんじゃいましたが、偽物だと聞いて安心しました。

> bind の _1 と boost::lambda の _1 は別物ですけど、それは認識されてますか?
全力で混同してましたー。っちゅーことは、

 ・bindの_1は「後で引数が入るところ」
 ・boost::lambda::_1は「後で引数が入るところ」かつ「それ自体が関数オブジェクト」

みたいな感じなんですかね。

> Method func1 = boost::bind(func0, _1 * 2);
> が正しそうだけど、無理ですねぇ。
はい、理解しました。
で、僕もやってみました。同じくうまくいきませんでした。
んー、くやしい。
もうちょい粘ってみます。


レスしてくださった方々、ありがとぅーん。
解決済み
引用返信 編集キー/
■8832 / inTopicNo.8)  Re[7]: delegateをboost::lambdaでやってみたい
□投稿者/ 囚人 (201回)-(2007/10/11(Thu) 10:06:26)
>boost::lambda::_1は「後で引数が入るところ」かつ「それ自体が関数オブジェクト」

いや、先の例で言うと「2 * boost::lambda::_1」という式自体が関数オブジェクトになるんじゃないかな。lambda の実装は凄すぎて私ではどうなっているのか分かりませんが。

bind も単にカリー化したいときに使うのであって、その用途で使うのはちょっと変ですね。

やるとしたら、こう?
boost::function<int(boost::function<int(int)>)> func1 = func0(2 * boost::lambda::_1);

コンパイルできるか分かんないですけど。

引用返信 編集キー/
■8881 / inTopicNo.9)  Re[8]: delegateをboost::lambdaでやってみたい
□投稿者/ デフォルトの名無し (4回)-(2007/10/12(Fri) 12:56:17)
C#のコードを見ると、func0とfunc1の両方ともintを受け取ってintを返す関数なので、
C++の方も両方ともfunction<int(int)>でいいと思うんですよね。
どういう書き方すればコンパイル通るのか分からないんですが。

bind(func0, _1 * 2);
って書いて、func0の引数に_1 * 2の結果(int)が渡されることを期待しているんですけど、
それが無理なんですかねー。
コンパイルエラーのメッセージを見ると、「演算子*は_1と2に適用できないYO!!」みたいなのがあったので、
2をかけるのがNGなんですかね。
実際、bind(func0, _1)だったらコンパイルできるし。

C++の次期標準では
 lambda::_1 + lambda::_2

 <> (int x, int y) -> int { return x + y; }
って記述可能だそうですね。
このコードの戻り値が関数オブジェクトなら、もっと素直に(?)
 func0 = <>(int n)->int{return n;};
 func1 = <>(int n)->int{return func0(n*2);};
とかできるんですかねー。
<>とか->とか使うのやめて欲しいですけど、でもboost::lambda使うよりかは直観的に分かりやすいと思います。


> bind も単にカリー化したいときに使うのであって
素人の僕の場合、カリー化というと複数引数のうち第1引数だけを固定して第2引数以降を受け取る関数を返す関数を作るイメージで、
例えば
int hoge(int a, int b, int c);
から
bind(&hoge, 10, _1, _2); // カリー化
みたいな。
だけど、bindってもっと汎用的で、カリー化だけでなくて
bind(&hoge, _3, _1, _2); // 引数の順番を入れ替える
bind(&hoge, _1, _3, _1); // 複数回使う引数や使わない引数がある
bind(&hoge, _1, 10, 20); // 束縛する引数を第1引数以外にしてみる
とかもできるみたいですし、(こんな用法が必要に迫られることがあるのか知らないけど)
あと、bindの引数にbindの結果を与えてやれば合成関数も作れるらしいですね。
引用返信 編集キー/
■8891 / inTopicNo.10)  Re[9]: delegateをboost::lambdaでやってみたい
□投稿者/ lol (1回)-(2007/10/12(Fri) 15:17:35)
int main()
{
	boost::function<int (int)> f1 = (boost::lambda::_1 * 2); //2倍して返す lambda式
	boost::function<int (int)> f2 = boost::bind(f1, ::_1); //::_1には f2() の第一引数

	std::cout << f2(10);

	return 0;
}

引用返信 編集キー/
■8900 / inTopicNo.11)  Re[10]: delegateをboost::lambdaでやってみたい
□投稿者/ デフォルトの名無し (5回)-(2007/10/12(Fri) 18:27:03)
> int main()
> {
> boost::function<int (int)> f1 = (boost::lambda::_1 * 2); //2倍して返す lambda式
> boost::function<int (int)> f2 = boost::bind(f1, ::_1); //::_1には f2() の第一引数
> std::cout << f2(10);
> return 0;
> }


えーとですね、僕がなぜこんな実用的でないプログラムに執着しているかといいますと、
いわゆる「継続渡し」で階乗を求める以下のSchemeの関数をC++のboostを使ってやってみたかったからです。
たんなる頭の体操です。
(define Fact
 (lambda (n cont)
  (cond
   ((= n 0) (cont 1))
   (else (Fact (- n 1) (lambda (m) (cont (* m n))))))))

これで5の階乗を求めるときは
(Fact 5 (lambda (m) m))
ですね。

boostやC++はあまり詳しくないので、直接やると分からなくなると思い、とりあえずC#で書き直しました。
delegate int Method(int n);
static public int Fact(int n, Method method)
{
 return n==0 ? method(1) : Fact(n-1, delegate(int m){return method(n*m);});
}
てな感じになるかと思います。
使うときは
Fact(5, delegate(int m){return m;});
です。

これを、C++でやろうとしてたんですねー。
Fact(5, 継続);
の値を求めるとき、func0はn==5のときの継続そのものなんでいいんですが、次のステップであるn==4のときの継続の書き方が分からなくて、とりあえず単に2をかける関数を作ってみるか、ってな感じで書いてたんです。
なので、func0の定義自体はいじりたくないんですよ。
あくまで、func0はboost::lambda::_1であって欲しいんス。
同じ要領で、使うときは
Fact(5, boost::lambda::_1);  // 継続のfunc0
ですね。

int Fact(int n, boost::function<int(int)> cont)
{
 return n==0 ? cont(1) : Fact(n-1, cont(boost::lambda::_1 * n));
}
ってやってみたり、
int Fact(int n, boost::function<int(int)> cont)
{
 return n==0 ? cont(1) : Fact(n-1, boost::bind(cont, _1 * n));
}
ってやってみたり。
んー、わけわからんッ。


あ...、
Fact関数のローカル変数で一時的にboost::function<int(int)>オブジェクトを作っといて、
そいつをboost::bind、boost::lambda、引数のcontでゴニョゴニョやって、
最終的にlolさんの案のようにboost::bind(tmp, _1)なんてできるのかなぁ。
でも、できればC#やSchemeみたいに簡潔に1行で書きたい。
むずいなー。

って、カテゴリを「雑談」にしたい気分。

解決済み
引用返信 編集キー/
■8913 / inTopicNo.12)  Re[11]: delegateをboost::lambdaでやってみたい
□投稿者/ lol (2回)-(2007/10/13(Sat) 14:41:25)
> これで5の階乗を求めるときは
> (Fact 5 (lambda (m) m))
> ですね。

int main()
{

	boost::function<int(int)> fact = boost::lambda::ret<int>(boost::lambda::if_then_else_return(boost::lambda::_1 == 1, 1, boost::lambda::_1 * boost::lambda::bind(boost::ref(fact), boost::lambda::_1 - 1)));
	std::cout << fact(5);

	return 0;
}

引用返信 編集キー/
■8922 / inTopicNo.13)  Re[12]: delegateをboost::lambdaでやってみたい
□投稿者/ デフォルトの名無し (6回)-(2007/10/13(Sat) 19:32:31)
うぉー、すげぇ。
boost::lambdaによる関数オブジェクトの()演算子の戻り値の型を明示する方法、初めて知りました。
他にも知らない関数がいくつかあります。嬉しいです。
このままじゃコンパイル通らないですが、参考にさせてもらいます。

でもこれって再帰関数なんですけど、継続渡しではないですよ。
int Fanc(int n)
{
 return n==1 ? 1 : n * Fact(n-1);
}
に相当するものを関数オブジェクトとしてローカルに用意してるんですよね。


まだ納得いく答えが出せていないので、いろいろ考えてみます。
ありがとうございました。

解決済み
引用返信 編集キー/
■8995 / inTopicNo.14)  Re[13]: delegateをboost::lambdaでやってみたい
□投稿者/ デフォルトの名無し (7回)-(2007/10/16(Tue) 01:42:49)
やったどー!!
やっと解決したどー!!

分かってる人には、そんなことで何日も...と思うかもしれませんが。
悩んで悩んで自分で答えを出せた時は嬉しいですねー。
ということで、誰も見てないかもしれませんが、一方的に結果報告させていただきます。

#include <iostream>
#include <functional>
#include <boost/bind.hpp>
#include <boost/function.hpp>
#include <boost/lambda/lambda.hpp>

namespace
{
 // 継続渡しで階乗の計算(継続は参照渡しの方がいいかも)
 int fact(int n, boost::function<int(int)> cont)
 {
  return n==0 ?
   cont(1) : fact(n-1, boost::bind(cont, boost::bind(std::multiplies<int>(), _1, n)));
 }
}

int main()
{
 // 5の階乗を標準出力へ
 std::cout << fact(5, boost::lambda::_1) << std::endl;
 return 0;
}


C#で書くと、
delegate void Method(int n);
int Fact(int n, Method cont)
{
 return n==0 ?
  cont(1) : Fact(n-1, delegate(int m){return cont(n*m);});
}
となりますが、n!=0のときのFactの戻り値である
Fact(n-1, ほげほげ)
の「ほげほげ」の部分は合成関数なわけですね。
っちゅーことで、boost::bindを2段でやってみました。

これまでレスポンスくれた皆さん、ありがとうございました。
解決済み
引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -