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

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

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

Re[4]: boost::bindで束縛される引数の規則性


(過去ログ 22 を表示中)

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

■9477 / inTopicNo.1)  boost::bindで束縛される引数の規則性
  
□投稿者/ デフォルトの名無し (8回)-(2007/10/28(Sun) 16:32:22)

分類:[C/C++] 

2007/10/29(Mon) 01:01:41 編集(投稿者)

boost::bindに関しての質問です。
分類にもあるように、C/C++に関してです。.NET絡みの話題ではありません。

たとえば、sqrt(x*x+y*y)を計算するファンクタを関数合成で作ってみます。
(秀和システム「Boost C++ Library プログラミング」、315ページより引用してます)

using namespace std;
using boost::bind;
using boost::function;

double x =
 bind(&sqrt
   bind(plus<double>(),
     bind(multiplies<double>(), _1, _1),
     bind(multiplies<double>(), _2, _2)))(3, 4);

としたとき、なぜ_1が3に_2が4に置き換わるのでしょ?

bind(multiplies<double>(), _1, _1)(x)ってやるとx*xが計算できますね。
bind(multiplies<double>(), _2, _2)(y)ってやると、コンパイルエラー。
そりゃそうですよね。だってbind(multiplies<double>(), _2, _2)は引数を2個とる関数オブジェクトだから。
でも、現にコンパイルに成功してxが求められてるってことは、
_2は一番外側のbind()で作られるファンクタの第二引数のためのプレースホルダなんですよね。
bind(multiplies<double>(), _2, _2)やそれ以外のbind()の第二引数のプレースホルダではないんですよ。
前もって関数の意味が与えられているので、そこから推測はできますが。
同様に、_1もbind(multiplies<double>(), _1, _1)や他のbind()の第一引数ではなく、
一番外側のbind()の第一引数なんですよね。_2と違いコンパイルエラーこそ起きませんが。
これが理解出来んのです。

ということで、
 ・いくつもbindがあるのに、_1等がどのbindで生成されたファンクタの引数にバインドされるのか
が分かりません。
今回の例では関数の意味から推測できるのですが、関数の意味が分からない場合はどうしようもありません。
なので、より具体的に言うと、私は
 ・_1等が引数にバインドされるときの規則性
が理解できていない、と言えると思います。

だれか分かる人、気が向いたらでいいので教えて下さい。
よろしくお願いします。

引用返信 編集キー/
■9493 / inTopicNo.2)  Re[1]: boost::bindで束縛される引数の規則性
□投稿者/ mあ@反省中 (2回)-(2007/10/29(Mon) 00:39:44)
2007/10/29(Mon) 01:10:53 編集(投稿者)

No9477 (デフォルトの名無し さん) に返信

http://www.boost.org/libs/bind/bind.html
http://www.boost.org/boost/bind/arg.hpp
http://www.boost.org/boost/function.hpp

ということらしいです。
引数の左からの順番を表しているとか。
function(b,_2,_2)(x) がダメなのは、引数が1個しか無いから。

include <> の中身をboost.org/ に続けてやると、そのライブラリのソースが、
libs/ 以下に続けて書くと HTML の使い方が出てきます。
こーゆーやり方は便利でいいなぁ。

http://www.boost.org/boost/function/function_template.hpp

すんまそん。あとは上のソース追いかけて下さい。目がしょぼしょぼしてきた・・・

bind.html の トラブルシューティングとこに少し書いてある希ガス。

きっと、、
boost::bind(&sqrt, _3, _2)(x,y,z); //OK なんじゃ?

int f(int);
boost::bind(f,_2); //これもOKなんじゃ?



引用返信 編集キー/
■9494 / inTopicNo.3)  Re[2]: boost::bindで束縛される引数の規則性
□投稿者/ デフォルトの名無し (9回)-(2007/10/29(Mon) 01:16:48)
No9493 (mあ@反省中 さん) に返信
> 引数の左からの順番を表しているとか。
> function(b,_2,_2)(x) がダメなのは、引数が1個しか無いから。
返信ありがとうございます。
一応、そのことについては承知しています。
function<double(double,double)> func = bind(multiplies<double>(), _2, _2);
としたら、
double func(double x, double y){retur y*y; }
と同じ意味のファンクタですよね。
これを
func(y);
って呼びだそうとしているからNGなわけですよね。

> あとは上のソース追いかけて下さい。目がしょぼしょぼしてきた・・・
とにかく、ドキュメント読むことは大事ですよね。
すみません、まったく読んでませんでした。
英語は激しく苦手ですが読んでみます...。
引用返信 編集キー/
■9500 / inTopicNo.4)  Re[3]: boost::bindで束縛される引数の規則性
□投稿者/ 囚人 (210回)-(2007/10/29(Mon) 10:37:35)
nested bind は内側から評価されますので、

まず、

x = bind(multiplies<double>(), _1, _1)(3, 4);
y = bind(multiplies<double>(), _2, _2)(3, 4);

が評価されます。その結果(上記で言えば、x、y)が次の外側の bind に評価され

z = bind(plus<double>(), x, y);

その結果 z が更に

bind(&sqrt, z);

となるわけです。

一般化すると
f(g(h(_1, _2, _3, …)))(x,y,z,…)

f(g(h(x, y, z,…)))

従って

>_2は一番外側のbind()で作られるファンクタの第二引数のためのプレースホルダなんですよね。
>bind(multiplies<double>(), _2, _2)やそれ以外のbind()の第二引数のプレースホルダではないんですよ。
>前もって関数の意味が与えられているので、そこから推測はできますが。
>同様に、_1もbind(multiplies<double>(), _1, _1)や他のbind()の第一引数ではなく、
>一番外側のbind()の第一引数なんですよね。_2と違いコンパイルエラーこそ起きませんが。

ではなく、「_1, _2 は一番内側のプレースホルダ」、「3, 4 は一番内側の bind に渡される引数」が正しいかなと。


引用返信 編集キー/
■9527 / inTopicNo.5)  Re[4]: boost::bindで束縛される引数の規則性
□投稿者/ デフォルトの名無し (10回)-(2007/10/29(Mon) 21:47:43)
2007/10/29(Mon) 22:29:11 編集(投稿者)

> 一般化すると
> f(g(h(_1, _2, _3, …)))(x,y,z,…)
> →
> f(g(h(x, y, z,…)))
って説明で、なんだか解ってきたかも!

じゃあ、
double Add(double,double); //足し算
double Mul(double,double); //掛け算
double Sub(double,double); //引き算
のとき、
Add(x, Mul(Sub(y, x), z));

bind(Add, _1, bind(Mul, bind(Sub, _2, _1), _3))(x,y,z);
と等価なのかなー、と思い立ち、実験してみました。
んで、結果、同じになりました。

function<double(double,double,double)> func =
 bind(Add, _1, bind(Mul, bind(Sub, _2, _1), _3));
double a = func(x,y,z);
とするとき、_1はx、_2はy、_3はzなんですね。
_1や_2などプレースホルダは、いちばん内側のbind()に全部なければイカンっちゅうわけではないのですね。


ここにきて、やっと自分の「モヤモヤ感」が何なのか見えてきた感じがします。
というのは、率直に言えば、
function<double(double,double,double)> foo =
 bind(Add, _1, bind(Mul, bind(Sub, _2, _1)(b, a), _3));
double b = foo(x,y,z);
なんてのはどうなのか、と。
bind(Sub, _2, _1)(b, a)の部分の_1と_2はxとyじゃなくてaとbなんですよね。
(果たして、このコードが有益になる場面があるのかは分かりませんが...)
_1やら_2やらのスコープ(って言っていいのかな?)に関してずっとモヤモヤしてました。


んで、もっと推し進めて、
function<double(double,double,double)> bar =
 bind(Add, _1, bind(Mul, bind(Sub, _2, _1)(b, _1), _3));
double c = bar(x,y,z);
はどうなんだ、と。
これはうまくいきませんでした。
bind(Sub, _2, _1)(b, _1)
において、_1にはxが充てられるものと期待したのですが。


ともあれ、かなり頭の中がすっきりしました。
コメントをくださったmあ@反省中さん、囚人さん、ありがとうございました。

解決済み
引用返信 編集キー/


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

このトピックに書きこむ

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

管理者用

- Child Tree -