結局C++とRustってどっちが良いの?
レス数が950を超えています。1000を超えると書き込みができなくなります。
C++の色々配慮してめんどくさい感じは好きだけど、実務になったらメモリ安全性とか考えて今後Rustに変わっていくんかな? >>846
それはjsとかRubyとかPythonではvtableじゃなくてハッシュテーブルを使ってメソッド呼び出ししてるって意味ですよ >>848
それは字面に囚われていて本旨を捉えていないと思うよ
例えば憲法第二十四条第一項は「婚姻は、両性の合意のみに基いて成立し」を
根拠にして同性婚は憲法違反と主張するようなもの >>850
示してくださった定義>>846には
ランタイム型情報に基づく場合が動的ディスパッチですよね
しかしSomeもNoneも静的に決まっているenum Option型の中の話ですからランタイム型情報は使っていません
したがってenumのmatchは動的ディスパッチに該当する要素が全くないため、動的ディスパッチではありません、という結論になります >>854
これだったら、yylvalでいいよね。。
もうちょっとない? >>853
コンパイル時にその後の振る舞いが決まるかどうかに興味があって
それを動的か静的かと呼んで議論しているんじゃないのかな? >>855
これパーサじゃないです……yylvalでよくないです……
イチャモン付けたいだけならもう返しません…… 結局まとめるとこうかな?
静的ディスパッチ ← 静的に型情報が決まる場合にコンパイル時に呼び出しメソッドが確定すること
動的ディスパッチ ← 動的に型情報が決まる場合に実行時に呼び出しメソッドが確定すること
Rustのmatch文でのenumの分岐は静的に型情報は確定しているけど呼び出しメソッドを決めるわけではないので静的ディスパッチではない
Rustのmatch文でのenumの分岐は静的に型情報は確定しているため動的に型情報が決まる動的ディスパッチとは無縁
つまりRustのmatch文でのenumの分岐はどちらのディスパッチでもなく一つの型の中の値による条件分岐にすぎない >>858
型情報による条件分岐に限らず値による条件分岐も動的ディスパッチだよ
なぜならC++の場合typeid演算子で取ったtypeinfoオブジェクトで条件分岐したら
それは型情報なのか値なのか?両者に差はないから >>859
-両者に差はないから
+両者を分ける意味はないから >>859
この場合のディスパッチとは型情報に基づいて呼び出しメソッドを決定すること
それが静的に決まれば静的ディスパッチ
そして動的に決まれば動的ディスパッチ
型情報に基づかなければ単なる昔からの条件分岐プログラム
typeidで得られるのは型情報なのでtypeidに基づくならば動的ディスパッチに該当する 条件分岐は条件分岐でしかない
ディスパッチは条件分岐を用いずに振る舞いを切り替えること >>861
typeinfoの実装見てみ
環境違ってもそんなに変わらんと思うから >>864
ちゃうやろ
比較で分岐するか
次の振る舞いがあるところに飛ぶか >>863
型情報を整数値で表すのは当たり前だけど
それは型情報ではない普通のデータの整数値の分岐とは話が全く違う
型情報によって呼び出すメソッドが変わるからそれを決定することをディスパッチと呼ぶ
その型情報が静的に決まるか動的にきまるかの違いのみ
typeidを使っているならば型情報が動的に決まっているのだから動的ディスパッチ >>834
そもそもそれをディスパッチと普通呼ぶ?
やってることはvtable使った動的ディスパッチも似たようなものだから
動的ディスパッチの一種とすることにそこまで違和感はないけど
広く浸透してる定義ではないよね 名称はともかくmatchの分岐はコンパイル時に決まらず
実行時に比較のオーバヘッドがある認識は共通しているので
何も対立はないはず
C++のmatchの話にもどしましょ >>868
>型情報を整数値で表すのは当たり前だけど
>それは型情報ではない普通のデータの整数値の分岐とは話が全く違う
わかんねーよw もういいよ まず>>846のstatic dispatchのページからとって来た文章をdynamic dispatchの「定義」として参照するのが間違い
こりゃすでにdynamic dispatchが定義された前提の上で、static dispatchと異なる点を書いているだけだよ
自分の思い込みを肯定するために都合良く文章を解釈してしまうのは人間やりがちだけどね >>867
ディスパッチは条件により分岐しない
渡された振る舞いを実行するだけ
例えば>>841のサイトのspeakに分岐処理は無いでしょ 話は簡単
まず前提「オーバーロードにより型が決まらないと呼び出す実メソッドが決まらない」
つまり「型情報が決まると呼び出すメソッドが決まる」
この決定のことをディスパッチと呼ぶ
静的に型情報が決まる場合は静的ディスパッチが可能
動的に型情報が決まる場合は動的ディスパッチとなる
型情報と関係ない話はどちらでもない >>874
> まず前提「オーバーロードにより型が決まらないと呼び出す実メソッドが決まらない」
> つまり「型情報が決まると呼び出すメソッドが決まる」
> この決定のことをディスパッチと呼ぶ
ここだけ読むとオーバーロード解決に聞こえるねw
https://ja.cppreference.com/w/cpp/language/overload_resolution Visitorパターン=多重ディスパッチ説があったからそれが元凶だろう
複数のメンバー関数から一つ選ぶのもディスパッチ
だから多重という 動的ディスパッチや静的ディスパッチは
何をディスパッチするのか考えなよ Rustは普通に書くだけでこのスレで言うところの静的ディスパッチとなりコンパイル時点で単相化されて速い
実行時にしか型が判明しない場合に対してはdyn指定による動的ディスパッチが可能でvtableが使われる
vtableを避けたいならばenumに包むことで直和型として収容して扱うこともできる vtableの持ち方がRustとC++では違うんだよね >>877
SpringやFluxのディスパッチャーだったり
Grand Central Dispatchだったり
何に対しても使える用語だから
区別できてない人もいるんだろう C++では、クラスが仮想関数を持つ場合、そのクラスのインスタンスに対して仮想関数テーブルが作成される。
仮想関数テーブルには、仮想関数へのポインタが含まれインスタンスに対して仮想関数が呼び出されるたびに
vtableを参照して適切な関数が呼び出される。
Rustでは動的ディスパッチを実現するためにトレイトオブジェクトが使用される。
トレイトオブジェクトには、traitオブジェクトが実装する各メソッドに対応するポインタのリストが含まれていて
インスタンスに対してメソッドが呼び出されるたびに、トレイトオブジェクトが参照され
適切なポインタが見つかるまでリストを検索し適切な関数が呼び出される。
結果は同じ。 >>882
詳細の説明がいろいろおかしいと思うけどどこソースなの? >>882
クラスとインスタンスの関係を理解してないな
C++の説明もRustの説明も同じように間違ってる
おまえオブジェクト指向を理解してなさそうと言われてたやつだろ >>882
うーむひどいな
とりあえずRustについて、この部分の間違いはあまりにひどい
> traitオブジェクトが実装する各メソッドに対応するポインタのリストが含まれていて
> 適切なポインタが見つかるまでリストを検索し適切な関数が呼び出される。
Rustは常にメソッドが静的に一意に確定するため、動的ディスパッチでも適切なポインタが見つかるまでリストを検索する必要がない
Rustはメソッド名が衝突する場合、まず自分の定義優先で確定、なくてトレイト間に衝突がなければ確定、衝突があればエラーだが、トレイト名を指定することでどのトレイトのメソッドでも常に利用可能
つまりRustではメソッド呼び出しが自分のメソッドかどのトレイトのメソッドかが静的に一意に確定する
静的ポリモーフィズムとして使われるときは、必要とする最小限のトレイトを列挙(=トレイト境界)するため、メソッドの衝突の可能性は通常時よりも減ったり無くなったりする
いずれにせよ上述したようにメソッドは静的に一意に定まるため、静的ディスパッチでは単相化(モノモーフィゼーション)されてコンパイルされる
動的ポリモーフィズムとして使われるときは、現在の仕様では指定できるトレイトは(auto traitを除き)一つのみに限定されている
ただし必要とするトレイトを列挙(=トレイト境界)したダミーなトレイトを任意に作ることも可能なため、事実上は複数のトレイトを指定できるのと同じ
指定トレイトが一つに限定されているということは、(そのトレイト境界を含めた)トレイト群すべてのメソッドを静的に一斉に把握できることを意味する
つまりRustのvtableはその指定トレイト一つのみに定まり、その親や祖先のvtableを辿る必要がなく、呼び出すメソッドは静的に確定してインデックス値となっているため、動的ディスパッチでも高速にメソッドを呼び出せる 間違ったことを書いてる人は完全に悪いけど、内容があれば議論のネタになるからまだマシ
それに対して間違ってる!とか、虚言!とかだけ言う連中は全く役に立たないから無視してよい
なぜなら、正しいことが書かれている場合でも、間違ってる!とか適当なこと言ったりするだけの連中も多いため >>886
> つまりRustのvtableはその指定トレイト一つのみに定まり、その親や祖先のvtableを辿る必要がなく
C++も同じです
> 動的ディスパッチでも高速にメソッドを呼び出せる
何と比較して?静的に比べりゃどうやったって遅いしそこにC++との差はないはずだし
不合格
>>887
テキトーかどうかの検証のために、出典を貼っていただけるとみんなが助かります
やるつもりが無いなら頃合いを見てマサカリを投げさせていただきます >>888
そういう意味のない言いがかりはやめとけ
元の>>882が正しくないこと「適切なポインタが見つかるまでリストを検索」と書いているので、
それに対して正しいこと「親や祖先のvtableを辿る必要がなく、動的ディスパッチでも高速にメソッドを呼び出せる」と書いた
そこで「静的に比べりゃどうやったって遅い」と頓珍漢なことを言い出すのは理解力のない証拠
これ以上は相手にしない OpenCV-rs ってもうメンテされてないんか?
gdgd なんだが >動的ディスパッチ
もしかして
遅延バインディング おじオジ言ってる人は頭がおかしいと他のスレで習ったけどここでもそうなの? てかよく読んでみれば>>882自体は「適切なポインタが見つかるまでリストを検索」としか書いてなくて
具体的にどういうリストなのかの説明は一切無し
なのになぜか>>886は「親や祖先のvtableを辿る」と、親子関係でリストができる?のを何故か仮定している
そういうことだよねw >>887
「最初から間違ってると思ってた」と事後に言うと、本当に最初からだったのかが真偽不明になるから
内容がなくても時刻を記録するだけで意味があるんだよ 祖先のテーブルをたどっていく実装や言語あるよ
特にJavaScriptはメソッドを後から生やせるから大変だった >>896
とりあえず、プライドは高いということは分かった >>887
どう見ても君が間違ってる本人じゃん
なぜバレないと思ったの? 1. 知ったかぶりして嘘をさも本当かのように書き連ねる
2. 間違いを指摘されるとググって必死に正解を探す
3. そしてそんなことは最初から知ってましたというトーンで長文まとめスレを他人のフリして書く
これが複オジメソッド >>900
そして話の内容がC++になると複おじにはちんぷんかんぷんなので
調べても間に合わないし、無限に別の間違いを生み出し続けてしまうというw >>899
俺が間違ってるって??
>>886に間違ってるところがあるなら指摘してくれ >>900
4. 他人のふりして書いた長文まとめも間違っている
というオチ付き >>902
その「間違ってる本人」は>>882のことを指していて、間違いがあるのは>>886のことではないと思うが
それはそれとして>>886の間違いを指摘しておくと
あなたC++で「どのvtableを見るべきか」を実行時にしか判断できないケースがあると思ってない? 嘘だよそれ
じゃないと「メソッドの衝突の可能性」なんて話が出てくる理由が無いと思うんだよね
そんなもんは静的に解決されて当然なのだから
ていうかね、参考にしたリンク貼ってくださいよって何回も言ってるでしょう
そのほうがあなたが(もしかすると私が)何を勘違いしているのかという答えにたどり着きやすいですって
いちいちあなたも長文で解説しなくて済むんですよ >>904
間違いがないのに間違いだと言い張る悪い癖はやめたほうがいいよ
冒頭に「Rustについて」と明記していてC++について一切記述していない
もしRustについて記述した>>886に間違いがあると主張するなら指摘してください
> 参考にしたリンク貼ってくださいよ
参考はRust公式ドキュメントとコードのみ
他の解説サイトがあるかどうか調べたこともないので知らない >>887
間違いがあるとタダで教えてくれるだけでも相当にありがたいことだと認識すべきだぞ
どこがどう間違えてるかをタダで懇切丁寧に教えてもらえると考えるのは甘えでしかない >>905
なるほどね?
例えば「検索する必要がない」「メソッドの衝突の可能性は通常時よりも減ったり無くなったりする」は対比的にそれらが「ある」存在に暗に言及しているのだと思ったよ
行間を読んで根本的に何を勘違いしているのか探ろうと思ったが、これはあくまでRustに関する言及でしかないと
「高速」も何と比較してなのか不明で虚しい響きがあるが、高速だというならそうなんだろう
じゃあ私から言えるのはこれだけです
> Rustは常にメソッドが静的に一意に確定する
じゃあRustに動的ディスパッチなんて実装する必要無いじゃん
dyn存在意義無いじゃん
「『トレイトとメソッド名のペア』が一意に確定する」ならそう書かないと、この文脈でこの表現は語弊しか無いよ 自分が長文を書きたいのではなく、相手に自分の真似をさせたいんじゃないか
知らんけど
真似してくれれば人間皆どっちもどっちだと実証されるかも知れないから ぽまいら一人一人が要点を絞ってくれ
発散させあってたらきりがないんよ
余計なことは省くこと
余計じゃないものが複数あってもより大事なほうを一つ選んで議論を続行すること >>904
メソッド名が衝突した時にどうなるか?どう対応できるか?は
各言語によって異なるから
その説明があるのは普通じゃないか
alias付ける必要があったりなど十人十色 動的ディスパッチするために必要な間接参照の数はRustもC++も同じで高速とか低速とかないから
Rustは動的ディスパッチを使う場合は必ずポインタ経由になるので構造体のデータを読むのに間接参照が1回必ず入る
これが持ち方の違いによって出る差の一つ あ、多重継承のケースがあったか
でもまあ気にするようなオーバーヘッドじゃないよね >>907
後半の指摘については、短い中で詳細まで説明できていないから誤解を与えてしまったもしれないので、そこはすまん
しかしその指摘だとまだ別の誤解されてそうだからその部分についてだけ一応書いておくと
ある型Fooのメソッドmethodの各呼び出しがそれぞれ異なっていてもよくて
Foo::method() なのか
<Foo as Trait1>::method() なのか
<Foo as Trait2>::method() なのかが決まり
Foo::method()がなくてそれ以外が複数で曖昧な時はエラーになるというだけの話
いろんな言語があるからね >>913
具体型Fooが確定している状態で動的ディスパッチは絶対に発生しません
dynと目印のついたトレイトオブジェクト経由でしか動的ディスパッチは発生しません
そしてこのときトレイトは確定しているのでメソッド名は衝突しません
だからメソッド名の衝突の話が出てくる意味が分からないと言っているんです >>912
多重継承の場合はどうなるの?
そこが焦点な気がしてきた >>914
ちゃんと>>886を読みなよ
動的ディスパッチの話は最後の段落にしか書いていない >>914
それはRustの基本が理解できていない
トレイトオブジェクトでも当然メソッド名は衝突しうる
なぜ衝突するのかも>>886に書いてあるな >>900
そのメソッドは迷惑行為なので
間違いを信じそうな人がいる時だけ
レス内容が間違ってることのみを指摘するのが吉 そのムーブはわかってないけどとりあえずケチつけてんだなとしか思わないよ
指摘できないけど誰か論破してくれねーかなっていう情けない感じ >>914
ボロボロですよ
トレイト境界を勉強しましょうね >>916
>>882が「Rustでは動的ディスパッチを実現するために〜〜」という文脈だったから最初からその範囲の訂正しか書いてないんだと思ったよ
脈絡もなく余計な文章を足すとそれがどういう意図でそこにあるのか理解してもらえないから気をつけようね
>>917
ああ厳密にはそうだね、私が間違っておりました
動的ディスパッチには関係ない文脈で書いた文章だって聞いたんでそこはもうどうでもいいです >>921
だよねー
>>886は>>882の間違いを指摘できてるわけでもなく何の意味もない >>921
まだ理解できていないのか?
動的ディスパッチの時こそメソッド名の衝突に対しての処置が重要
そのためどのトレイトのメソッドを呼び出すかを静的に確定するとともに
各トレイトの同名メソッドを区別してvtableのインデックス化をしている >>924
>各トレイトの同名メソッドを区別してvtableのインデックス化をしている
うそーん
ソースを提示してね >>925
インデックス区別しないと動的ディスパッチできないですよ SubとSuper逆だわ
気になるなら直してていいよ >>914
バカだな
動的ディスパッチが行われるときは具体型Fooが確定しているぞ
具体型が確定しているからこそ動的ディスパッチを実行することができる
おまえC++もRustも両方を理解できてねーな >>926
トレイトオブジェクトを扱うためにBoxは不要
ヒープを使うのは必要性があるときのみ
求められているのは俺が書いた「各トレイトの同名メソッドを区別してvtableのインデックス化をしている」の部分だろ
それを直接わかるコードを書いた
ただしvtableはpubではないので現状の仕様を強引にアクセス
インデックス値の順序も変わる可能性ありなので注意
macro_rules! vtable_base { ($dyn:expr) => { *(&$dyn as *const _ as *const usize).offset(1) as *const usize } }
macro_rules! vtable { ($dyn:expr, $index:expr) => { unsafe { *(vtable_base!($dyn).offset($index)) } } }
trait TraitA {
fn method(&self);
}
trait TraitB {
fn method(&self);
}
trait TraitAB: TraitA + TraitB {}
struct Foo;
impl TraitA for Foo { fn method(&self) {} }
impl TraitB for Foo { fn method(&self) {} }
impl TraitAB for Foo {}
fn main() {
let foo = Foo;
let dyn_foo: &dyn TraitAB = &foo;
assert_eq!(vtable![dyn_foo, 3], <Foo as TraitA>::method as usize);
assert_eq!(vtable![dyn_foo, 4], <Foo as TraitB>::method as usize);
}
というわけで動的ディスパッチでもメソッド名衝突の話は必要であり>>886の説明で合っている >>930
単にvtableが作られることを「vtableをインデックス化してる」と言ってたのね
もう嫌だ >>931
助詞を間違えてるぞ
「各トレイトの同名メソッドを区別してvtableのインデックス化」な >>932
どっちでも間違ってる
インデックス化されるのはメソッド
vtableはメソッドがインデックス化されたデータ構造 >>933
だからそう書いてるだろ
文章も>>930のコードも読めないのか? C++からメタ言語機能のような黒魔術を無くして使いやすくしたのがRustという認識でよろしいか? ディスパッチがどうとか言ってるあいだに1000きそうだぞこれ
なんだかんだで実際は両方使うけど、やっぱ俺はこっち推すぜ! みたいなスレになりつつ
テンプレ用意すんの? 要するに「へぇ、継承ってのがあるのか、どうやって実現するんやろ?あ、オレならこうするな、でもそれだとこうなってコストメチャメチャかかるじゃん、使えねぇな」と思ってるくちじゃないの? その件は>>930が正しい
assert通るのを確認した >>930
言いたいことは理解した
でもね、そもそも「衝突」は定義だけで発生するものなんですよ
そのコードのmainの中でdyn_foo.method()と書くと発生するエラーは、「名前解決の失敗」と呼ばれます
そしてこの「衝突」の有り無しは、「vtableのインデックス化」に特に影響を与えません
現に片方だけメソッド名を変更しても、同じレイアウトになりますよね
内部的には別トレイトのメソッドなのだから、"method"部分が「衝突」するしないに関係なく区別されます
「衝突」に、vtableに関して特筆すべき重要性は無いと思います 静的型付けをしてればどのメソッド実装を呼び出すか静的に決まるのは当たり前のこと
それを何か特別なことのように変な長文書くからバカにされる C++er あるあるシリーズ
#![allow(unused)]
... = hoge().unwrap;
... = hoge()?;
let p: *const [u8] = &fuga;
unsafe {} >>937
ほんそれ
C++出来る人はC++使えば良い
C++出来ない人やC++でやらかすうっかりさんだけRust使えば良い 面白いのはC++ちょっとかじったくらいのド素人ほど
なぜかRustに引き寄せられてる気がする
ニワカ人間を引きつける同じニオイがするんだろうなRustには C++は底なし沼な感じが良い
未だにModern C++ Designを初めて読んだときの衝撃を上回る
本には出会ったことがない 職業マとアマチュアで感想違うよね
職業マ「C++? 糞の糞糞」
アマチュア「C++? vtableのコスト(キャッキャ)
鼻から悪魔(ウフフフ)膝を撃ち抜く(キャッキャ)CRTP(ウフフ) レス数が950を超えています。1000を超えると書き込みができなくなります。