- C++相談室 part129 [無断転載禁止]©2ch.net
663 :デフォルトの名無しさん (ワッチョイ f35b-tpgq)[sage]:2017/03/18(土) 11:02:56.09 ID:waR+gchT0 - >>657
std::transformならbindいらんだろ。イテレータを渡してる。 > https://cpprefjp.github.io/reference/algorithm/transform.html そしてこの場合、(someClass->*someMethod) と書けるしそれで十分だろ。 >>660 ここでbindも継承もないソースを上げてくることにびっくりだわ >>658-659 関数内でのthis.someFieldへのアクセスは継承してないと無理でしょ。 静的型ではポインタを生成出来ない。(動的ダックタイピングなら可能) http://www7b.biglobe.ne.jp/~robe/cpphtml/html03/cpp03057.html http://www.ibm.com/support/knowledgecenter/ja/SSGH3R_12.1.0/com.ibm.xlcpp121.aix.doc/language_ref/cplr034.html 継承してない物をbindして、その関数内からthis.someFieldにアクセス出来る例があるか? あればよろしく。
|
- C++相談室 part129 [無断転載禁止]©2ch.net
669 :デフォルトの名無しさん (ワッチョイ f35b-tpgq)[sage]:2017/03/18(土) 12:48:15.84 ID:waR+gchT0 - >>666
> std::vector<int> invoke(const std::vector<int>& v, const F& f) const > std::bind(&F::calc, f, _1, 2)); bindしている対象は F& f つまり自分自身のクラスだろ。 それは継承してるのと意味は同じだよ。(今回の問いにおいては) 俺はそこに全く無関係のクラス class G{} を突っ込めるのかと問うている。 C++では出来ないだろ。(JavaScriptでは出来る) 自分自身、または継承関係のあるクラスなら、 > std::bind(&F::calc, f, _1, 2)); のところを代わりに f->*calc と書けるんだよ。それでいいだろ、という話。 今回は引数が複数個で、第2引数を確定させたいみたいだから、 C++にその文法が無く、部分適用関数をあらかじめ用意するしかないようだけど、 それは文法が足りてないから。(ただしそこまで使わないのでbindでもいいが) ただそもそもカリー化して一個ずつ食えって話だろ、本来は。 その場合なら第2引数を確定させた関数を作る為に、 class H: F{ int k; int calc(const int x); } だろ。それで h->*calcで良いんだよ。(継承関係が有ればbind無しで書ける) というか内部的には同じ事をやっていると思っているんだが。
|
- C++相談室 part129 [無断転載禁止]©2ch.net
670 :デフォルトの名無しさん (ワッチョイ f35b-tpgq)[sage]:2017/03/18(土) 12:48:34.92 ID:waR+gchT0 - それで話を戻すと、
「継承関係無しで、自分自身でもないクラス G をbind出来るか?」 というのが俺の問いね。 お前は日本語にもこだわるタイプのようだから、「自分自身でもない」と明記しておく。 (これは普通に分かると思いたかったが) 要するに俺は、 「静的型であるC++に於いてthisのバインドって意味あるのか?」 と問うている。 動的型ならバインド後にメンバ追加して実行時に揃っていればダックタイピング可能だから意味がある。 静的型はバインドする時点でメンバが揃っていることを確定出来ないといけない。 それって要するに継承関係がないと無理だよね?という話。
|
- C++相談室 part129 [無断転載禁止]©2ch.net
671 :デフォルトの名無しさん (ワッチョイ f35b-tpgq)[sage]:2017/03/18(土) 12:51:40.31 ID:waR+gchT0 - × 静的型はバインドする時点で
○ 静的型はバインドが使われているソースをコンパイルする時点で 一応訂正しとくわ。分かる範囲だとは思うが。
|
- C++相談室 part129 [無断転載禁止]©2ch.net
674 :デフォルトの名無しさん (ワッチョイ f35b-tpgq)[sage]:2017/03/18(土) 13:31:02.22 ID:waR+gchT0 - >>672
> バインドしとかないと動かねーだろがよ その通りだ。 多分君はC++しか知らないから、それ前提で話をしているからそう思えるのだと思う。 これ自体は不思議ではない。 JavaScriptなら以下みたいなことが出来る。 var a = { a: 1, k: 2, calc: function(x){return this.k*x+this.a;} }; var b = {}; // bはaと継承関係なし var b_calc = a.calc.bind(b); // aのcalcにbをバインド ---(A) b_calc(3); // 実行可能、結果は NaN ---(B) b.a = 4; b.k = 5; b_calc(6); // 実行可能、結果は 34 ---(C)
|
- C++相談室 part129 [無断転載禁止]©2ch.net
675 :デフォルトの名無しさん (ワッチョイ f35b-tpgq)[sage]:2017/03/18(土) 13:31:20.02 ID:waR+gchT0 - C++から見ればデタラメだが、JavaScriptはこれでも動く。
C++は(A)の時点でバインド対象(今回はb)がcalcを動かしても問題ないことが必要で、 コンパイル時に確定させる為には通常は継承関係がないと無理だろ。 JavaScriptはそういうの関係無しにとりあえずbind出来る。 ただし中身が揃っていない時に実行したらNaNが返ってくる。(B) そして中身を揃えたあとには正しく実行される。(C) だからJavaScriptみたいな言語ならthisをバインドする意味があるのだが、 C++のように継承関係がないとメンバ関数を呼べないのなら、 常に f->*calc の形で記述することが可能であり、bind時にthisを確定させる意味がない。 (やってもいいのだが、冗長=糖衣構文) JavaScriptでは(B)の時点で b はメンバを何も持っておらず、 (C)の時点でもメンバは a, k のみで、calcはメンバではないことに注意。 (当たり前だが a を継承していれば calc もメンバになる)
|
- C++相談室 part129 [無断転載禁止]©2ch.net
677 :デフォルトの名無しさん (ワッチョイ f35b-tpgq)[sage]:2017/03/18(土) 13:38:41.49 ID:waR+gchT0 - >>673
> callbacks.push_back(std::bind(&A::func, &a)); これを、this側が関係ない奴、例えばBにして、 callbacks.push_back(std::bind(&A::func, &b)); // (D) だとコンパイル通らないだろ?(俺の予想だが) だったら、常にその場合は、 callbacks.push_back(a->*func)); と書けるよね?という話。 (もちろん糖衣構文ならそれでいいんだが) JavaScriptは(D)でもコンパイル通るんだよ。(まあコンパイル自体がないんだが) そして実行も出来る。(ただし実行時にメンバが揃ってない時にはお察しで)
|
- C++相談室 part129 [無断転載禁止]©2ch.net
679 :デフォルトの名無しさん (ワッチョイ f35b-tpgq)[sage]:2017/03/18(土) 13:53:42.63 ID:waR+gchT0 - >>676
見やすさの為に、というのはいい。 > thisのbindだけ疑問視する理由は? プログラミングコストが減ってないから。 auto a_func = std::bind(&A::func, &a) なら、 a を管理するか a_func を管理するかで、何も隠蔽出来てないし減ってない。 ただ>>673みたいな使い方だと、 型を揃えた結果、同じ記述で実行出来るから、この点は確かにメリットはある。 これを言いたかったのか?
|
- C++相談室 part129 [無断転載禁止]©2ch.net
683 :デフォルトの名無しさん (ワッチョイ f35b-tpgq)[sage]:2017/03/18(土) 14:04:04.03 ID:waR+gchT0 - >>678
ちょっと輻輳してて申し訳ないが、 > >callbacks.push_back(a->*func)) > と書けるようにしたらbindでthis使う必要ないって話? そう。というか継承関係ある状態でしかメンバ関数使えないのなら、 thisをbindする意味がないと思った。 (引数はbindしていいが、これもbindなしで継承でも書ける>>669) ただし、>>673みたいに、「戻り値と引数が同じなら同じ関数型」として扱えるのなら、 継承関係なしのA::funcとB::funcを同じに扱えるからやっぱbindしてないと駄目だな。 ところで、ここでクロージャを使うことに意味はあるのか? > callbacks.push_back([&]{a.func();}); もちろん使ってもいいが、a.funcがクロージャ内の変数を捕捉しているはずもないし、直接 > callbacks.push_back(a->*func)); で全く問題なくね?
|
- C++相談室 part129 [無断転載禁止]©2ch.net
691 :デフォルトの名無しさん (ワッチョイ f35b-tpgq)[sage]:2017/03/18(土) 14:20:22.86 ID:waR+gchT0 - >>681-682
> インスタンス構築 それはインスタンス構築ではなく、使う物だけとりあえず入れてるんだよ。 a を構築しているのではなく、 a.func の数式 k*x+a を使いたいから、 とりあえず a と k に値を入れて使っているだけ。 数式を間借りしているだけなんだ。 もっと a が複雑で、100個くらいメンバを持っているベクトル値だったとして、 calcも calc_0 〜 'calc_100 とかあったとして、そのうち1個だけ丁度いい数式があったら、それを借りる感じ。 このデタラメっぷりはC++にいると理解不能だが、JavaScriptに慣れるとC++が色々面倒で仕方ない。 そもそもテンプレートも型消去も最初からvarだとやらなくていいんだよ。 (その分デバッグが辛いが)
|
- C++相談室 part129 [無断転載禁止]©2ch.net
692 :デフォルトの名無しさん (ワッチョイ f35b-tpgq)[sage]:2017/03/18(土) 14:24:47.73 ID:waR+gchT0 - >>689
いやその文法はすでにC++0xにあるとの理解だが、これが間違いか? 既に>>663にURL上げたが。 > メンバーを指すポインター演算子 .* および ->* は、特定のクラス・オブジェクトのメンバーを指すポインターをバインドする際に用いられます。
|
- C++相談室 part129 [無断転載禁止]©2ch.net
695 :デフォルトの名無しさん (ワッチョイ f35b-tpgq)[sage]:2017/03/18(土) 14:43:08.69 ID:waR+gchT0 - >>684
ちなみに何でそれ書けないんだ? std::function<...> f_bound = a.func; // (E) バインド済み std::function<...> f_not_bound = A::func; // (F) 未バインド、第1引数はthis で文法的に問題ないし、普通にこうだと思っていた。 ただし俺はC++でメンバポインタを使ったことはないから、 現在駄目なのなら何か理由があるのだろうけど、 逆にそうだと信じ切っており、 JavaScriptはこれができない=常にbindが必要なのでウザくて仕方なかった。例えば、 var func = someInstance.someMethod.bind(someInstance); と常に2回 someInstance と書く必要があり、これがウザイ。 ただC++も同じく糞なのか?
|
- C++相談室 part129 [無断転載禁止]©2ch.net
698 :デフォルトの名無しさん (ワッチョイ f35b-tpgq)[sage]:2017/03/18(土) 15:44:12.23 ID:waR+gchT0 - >>696
インスタンスとクラスの違いが分かってないのはお前だろ。 >>695をJavaScriptで再記すると、 var a = new A(); var func_0 = a.func; // bindされない ← 直感的にはbind済みであって欲しい var func_1 = A.prototype.func; // bindされない ← これはOK で、JavaScriptは両方ともbindされないんだよ。 だから他言語から来た連中はbindを忘れてここでバグると言われている。 その「他言語」ってのは俺はてっきりC++だと思っていたから、695の理解になる。 ところがC++も同様に糞ならまあそれでよし。 改めて見ると、代入出来ないってことか?つまり、以下が出来ない。 std::function<...> f = a->*func; // bind済み std::function<...> f = a.*func; // bind済み なるほどC++も糞だな。ただ、実装自体は>>669で出来るのだから、 何故これを出来ないようにしたのかは謎だが。
|
- C++相談室 part129 [無断転載禁止]©2ch.net
701 :デフォルトの名無しさん (ワッチョイ f35b-tpgq)[sage]:2017/03/18(土) 16:02:10.31 ID:waR+gchT0 - なおC#ではあっさり書けることが判明した。
> class DelegateTest > { > static void Main() > { > Person p1 = new Person("鬼丸美輝"); > Person p2 = new Person("神無月めぐみ"); > > ShowMessage show = new ShowMessage(p1.ShowName); > show += new ShowMessage(p2.ShowName); > show += new ShowMessage(A); > show += new ShowMessage(B); > > show(); > } > > // 結果 > // 名前: 鬼丸美輝 > // 名前: 神無月めぐみ > // A が呼ばれました。 > // B が呼ばれました。 > http://ufcpp.net/study/csharp/sp_delegate.html
|
- C++相談室 part129 [無断転載禁止]©2ch.net
702 :デフォルトの名無しさん (ワッチョイ f35b-tpgq)[sage]:2017/03/18(土) 16:02:29.43 ID:waR+gchT0 - そしてC++でも出来そうなんだが、、、
> Human alice; > printf("Alice"); > (alice.*pf5)(); > > // おまけ > int Human::*x = &Human::age; > alice.age++; > printf("age = %d (%d)", alice.*x, &(alice.*x)); > http://qiita.com/Ted-HM/items/282785fcdcd06fb59642
|
- C++相談室 part129 [無断転載禁止]©2ch.net
703 :デフォルトの名無しさん (ワッチョイ f35b-tpgq)[sage]:2017/03/18(土) 16:27:36.88 ID:waR+gchT0 - >>699
> 似非^2オブジェクト指向じゃん? あれはクラスベースではなくプロトタイプベースだから。 それを無理矢理クラスベースとして使おうとするからおかしな事になる。 最初からプロトタイプベースとして使えば何も問題なく、 実際に表現出来る範囲もクラスベースよりも広いので、なかなか面白い。 > ちなC++の話として、クロージャはあんま継承関係無い JavaScriptでも継承とクロージャは全く関係ない。 > f.calc(x, 2)をfunc(x)の如く扱いたければfの所有でおk これはそうだと思う。 fがf_boundに変わっても手間は同じで、意味ねーというのが最初の主張。 >>700 > 個人的にはstd::bind(&F::calc, f, _1, 2)ですらF::calcの直接callに最適化されずに、 というかこれを期待するのがC++なのか? それはさすがに厳しいとは思うが、確かに無理ではないが。 > テンプレートを使える環境にありながら > 関数へのポインタなど使うのは教育上によろしくない これはどういう意味?さすがに今回の上記 > std::bind(&F::calc, f, _1, 2) をテンプレートで常に直接callするようには出来ないだろ。 というかテンプレートと関数ポインタの使う範囲は被らないと思うが。(代替出来ない)
|
- C++相談室 part129 [無断転載禁止]©2ch.net
705 :デフォルトの名無しさん (ワッチョイ f35b-tpgq)[sage]:2017/03/18(土) 16:38:53.29 ID:waR+gchT0 - ああ分かった。
>>702はこちらの解釈間違い、これは出来ているわけではないね。 .* と ->* はあくまでその場で呼んでいるだけであって、 bind済みの関数を返してくれるわけではないのね。
|
- C++相談室 part129 [無断転載禁止]©2ch.net
707 :デフォルトの名無しさん (ワッチョイ f35b-tpgq)[sage]:2017/03/18(土) 17:00:49.05 ID:waR+gchT0 - >>704
> 本質的には直接callとなるべきもの それを言いだしたら全部だろ。そうなってないから色々問題なわけで。 ただこれに関してはスタックイメージを揃えればいいだけだから、やる気だけだね。 最初からスタックイメージを揃える呼び出しを用意してもいいし、 一旦>>669の形式で2段階呼び出しにして、インラインにしてもいい。 (ただしインライン展開対象は外側関数なので従来最適化ルーチンは使えない) いずれにしても難しくはないよ。やる気だけの問題だね。
|
- C++相談室 part129 [無断転載禁止]©2ch.net
710 :デフォルトの名無しさん (ワッチョイ f35b-tpgq)[sage]:2017/03/18(土) 20:18:06.83 ID:waR+gchT0 - >>709
いや結局何が言いたいんだ? 君:700「std::bind(&F::calc, f, _1, 2)は最適化されないかも…」 俺:703「それを期待するのは厳しいだろ」 君:704「いやできるし、そうなるべきだ」 俺:707「そりゃそうだが」 人間が見れば簡単に分かることが出来ないなんて!なんてのは全部だよ。 一般的にはポインタになった時点で最適化が難しくなる。 f->calc(x,k); // 直接呼び出し std::bind(&F::calc, f, _1, 2)(x); // 直接呼び出し std::function<...> f; // (G) f = std::bind(&F::calc, f, _1, 2); // (H) f(x); // 2段呼び出し // (I) f = std::bind(&F::calc, f, 2, _1); // (J) f(k); // 2段呼び出し // (K) C++では「戻り値と引数」が合ってたら良いんだろ? だったら(G)はいけるよな? この場合、fには(H),(J)とも可能なんだよ。 バインドされているのは第1引数でも第2引数でもいい。 ところがこれを実行する際、直接呼び出しに展開する為には、 (I)と(K)で呼び出し方法を変えなければならない。 スタック上の引数の位置が異なるからね。 そして一般的には(H)(J)はどこか遠いところで代入されており、 通常はその関数外から与えられる。 だから最適化は難しいんだよ。
|
- C++相談室 part129 [無断転載禁止]©2ch.net
711 :デフォルトの名無しさん (ワッチョイ f35b-tpgq)[sage]:2017/03/18(土) 20:18:41.61 ID:waR+gchT0 - ローカル関数内でfが分かりやすく代入されている場合は完全に最適化出来る。
同様の方法で外部から与えられた場合でも常に最適化する為には、 fに代入される可能性のあるポインタを全て精査する事が必要だが、一般的にこれは無理。 (書いた本人には何が入る可能性があるか簡単に列挙出来るが、 ソースコードから抽出するのはかなり無理) したがって、次案としては、 f自体に「第○引数を第△引数に入れ替え、第●引き数は▲で固定」という情報を持たせ、 対応することになる。(なおこの操作を別関数として行うのが「2段呼び出し」になる。) もっとも、C++のメンバポインタはintサイズでなくてもいいみたいなので、 この方法でも出来なくもないが、VC++ではやってないね。 > VC++で試したところ、普通は4、多重継承していれば8、仮想継承していれば12となりましたが、 > http://www7b.biglobe.ne.jp/~robe/cpphtml/html03/cpp03058.html これをやっていれば通常でも4では済まない。 多重で増えているのはポインタのずれを補正する分だね。 > https://www.microsoft.com/japan/msdn/vs_previous/visualc/techmat/feature/jangrayhood/
|
- C++相談室 part129 [無断転載禁止]©2ch.net
712 :デフォルトの名無しさん (ワッチョイ f35b-tpgq)[sage]:2017/03/18(土) 20:19:09.95 ID:waR+gchT0 - 分かるか?
完全に「直接呼び出し」にするには動的データとして「メンバ関数オブジェクト」みたいな物を作り、 それの展開ルーチンをインラインで埋め込まないといけないんだよ。 (サブルーチンで呼び出すと結局2段呼び出しになるだけ無駄) だったらそのままその「展開ルーチン」→「ターゲットメンバ関数」の2段呼び出しでもいいや、ってことになるだろ。 それがVC++でこの部分の直接呼び出し最適化をしていない理由だと思うよ。 多分さほど効果がないんだよ。(やる事自体は難しくない) 表面的な原因は、「第1引数がbindされた関数ポインタ」「第2引数がbindされた関数ポインタ」が 同じ型になってしまうことだよ。だからといって、これらが別型なのは言語として糞だろ。 明示的に分かりやすくその場で代入されている場合は、 これらを別扱いすればいいだけだから比較的楽に対応出来る。 だけど一旦ポインタとして受けられた場合、どれになるかは分からなくなるので無理になる。 それで、ポインタ自体にその情報を与えて動的モドキで対応するよりも、 単純に2段呼び出ししたほうがマシ、という判断が為された、ということだよ。VCでは。 ただ、2段呼び出しは「継承したクラス」を自分で書いた場合で、 std::bindってevalするわけではなくて、静的なライブラリ(=データしか作成出来ない)だよな? だったら内部的に上記「メンバ関数オブジェクト」方式になっている可能性が高く、 2段呼び出しで汎用ルーチンで展開=一番遅いパターンだと思うけどね。 まあここら辺はそっちの方が詳しい気がするが。 で、改めて聞くが、何が言いたいんだ? 俺はCコンパイラを作っているわけではないし、俺に文句言われても知らんがな。 結論としては、 > std::bind()自体の書き方や関数オブジェクトの書き方がよほどアレでない限りはF::calc()直接呼出し相当のコードになる は間違いだね。理由は上記、完全精査はかなり難しいからだ。 (もし出来てるのならスゲーとは思うけど)
|
- + JavaScript の質問用スレッド vol.122 + [無断転載禁止]©2ch.net
684 :デフォルトの名無しさん (ワッチョイ f35b-tpgq)[sage]:2017/03/18(土) 22:47:45.17 ID:waR+gchT0 - >>683
onclickイベント関数の引き数eにclientXが格納されているからそれを見る。 https://developer.mozilla.org/en-US/docs/Web/Events/click https://developer.mozilla.org/en-US/docs/Web/Events 以下で試してみ。 document.getElementsByTagName('body')[0].onclick = function(e){console.log(e.clientX);};
|