結局C++とRustってどっちが良いの?
■ このスレッドは過去ログ倉庫に格納されています
C++の色々配慮してめんどくさい感じは好きだけど、実務になったらメモリ安全性とか考えて今後Rustに変わっていくんかな? >>780 動くコードじゃないと意味がないのでmain()付きの動くコードを示そうよ Rust版は>>772 >>781 パターンマッチングを全く行なっていないじゃん 例えば分かりやすくこの項目を増やすとして Shape::Rectangle(100, h) => println!("幅100で高さ{h}の長方形です"), これはC++でif (w == 100)のコードになるわけだよね それはパターンマッチングとは言わないよ >>782 enumのバリアント判定に相当するパターンマッチを行っていますので、全く行っていないという指摘は正しくありません また、>>748 のenum_patternにShape::Rectangle(100, h)にマッチするコードは含まれておらず、あなたの当初の要求に含まれていないものです 新しい要求を後から追加して批判するのは、誠実な態度とは言えません このようなことが無いように、「何が無理か」を明確にするよう確認したつもりでした 今後はこうしたことが無いように、事前よく確認することをお願い申し上げます また値によるマッチについてですが、同様の考えで似たライブラリを実装された方を見つけました こちらは値によるマッチに拡張したライブラリを実装されているようです https://qiita.com/Naotonosato/items/a1e710de2b78346146d1 >>781 かなり苦しいね >>748 の残り3つのパターンマッチングには応用できそうもないけど書ける? >>782 別に関数プロトタイプまで書いてるんだから分かりそうなものだけど... 以下は静的ディスパッチでコンパイル時に定まるよ >>772 が静的ディスパッチできないとしても たぶん同じように書けばRustでも静的にディスパッチできると思うよ #include <iostream> using namespace std; namespace Shape { struct Circle {uint32_t r;}; struct Rectangle {uint32_t w; uint32_t h;}; struct Parallelogram {uint32_t ui0; uint32_t ui1;}; template <typename T> void function (ostream &os, const T &p) {} void function (ostream &os, const Circle &p) {} void function (ostream &os, const Rectangle &p) {} } int main () { using namespace Shape; Circle circle; function (cout, circle); Parallelogram parallelogram; function (cout, parallelogram); return 0; } 静的ではなくて動的ディスパッチだろ このように次々と何が来るかわからないリストが渡ってきた場合 Shape::Shape shape_list[4]; shape_list[0] = Shape::Rectangle{w: 33, h: 33}; shape_list[1] = Shape::Parallelogram{ui0: 4, ui1: 33}; shape_list[2] = Shape::Rectangle{w: 33, h: 4}; shape_list[3] = Shape::Circle{10}; その時にこれで処理できるのだから動的ディスパッチをしている for (int i = 0; i < 4; i++) { enum_pattern(shape_list[i]); } >>786 静的ディスパッチと書いているのは俺が書いた>>762 と>>785 のC++の例 コンパイル時にどの関数が呼ばれるか型によって決まる もうちょっと調べてたが、C++にもinspectってのが来そうみたいじゃん パタンマッチングって、こんなもんが流行ってるのね、また一つ取り残されてたぜ >>786 いいえ、これは静的ディスパッチです 簡単に確認する方法として、生成されたアセンブリ中のvtableを確認する方法があります: https://godbolt.org/z/1W7jGnWEd "vtable for std::bad_variant_access:"が唯一のvtableであり、Circleなどのためのvtableはありません このことから、動的ディスパッチは発生しないことが分かります >>789 おいおい vtable使うことだけが動的ディスパッチだと思いこんでいるのか? 実行時にデータ内容に応じて分岐することを動的ディスパッチと言う >>786 はもちろん動的ディスパッチをしている 次に何が来るかはコンパイル時点で決まらないため静的に決定は不可能だ >>788 昔はなかなか規格としてまとまらなかったが最近のC++はどうした? 俺もboostに入ってたやつくらいしか追えていない >>790 それはRsutのコードか? C++のコードか? >>793 >>785 は静的ディスパッチだよ コンパイル時にどの関数が呼ばれるか定まる >>790 いいえ 動的ディスパッチとは、多態メソッドの呼び出し式を実行するときに、具体型に応じて実際に呼ばれる関数が振り分けられることを言います https://en.wikipedia.org/wiki/Dynamic_dispatch 動的ディスパッチはしばしばパフォーマンスの低下をもたらすと言われますが、その最大の理由は、 選択される各関数ポインタを一度メモリから(vtableから)読み出し、それをcallする必要があることです 動的ディスパッチをどう定義するかはさておき、vtableが無い>>789 ではこのパフォーマンス低下の懸念が無いことが分かります また、「実行時にデータ内容に応じて分岐することを動的ディスパッチと言う」という定義には明らかな問題があります それは、この定義ではmatchやifなど通常の制御構造も動的ディスパッチに当てはまってしまうということです これは、この定義が一般的な定義から大きく逸脱していることをよく象徴的に表わしています 少なくとも「データ内容」は「型」に置き換える必要があることが分かるでしょう >>789 それは動的ディスパッチだよ C++のstd::visitはstd::variantのindex()の値で実行時に分岐してる だから>>786 のような実行時になるまで何が来るか不明な場合にも対応できる >>791 inspectは、godboltでclangのexperimentalを遊べるようになってた 型に対しては、もうちょっとまだみたい、error: expected expression って言われた ラムダみたいに、みんなが欲しがるものはそれでもわりと早いんだよね 一応入れとくか…みたいのは、いつまでたっても入らないw ところで、godboltに、-Wlifetime ってのがみえたけど…これってもしかして C++の仕様を変えようという時に国語辞典の変更を許さないのはタイパ最悪だな C++の仕様変更を許さない、とすれば秒速で終わる >>796 いいえ、これは動的ディスパッチではありません 「実行時になるまで何が来るか不明な場合にも対応できる」ことは、それが動的ディスパッチであることの証明にはなりません 繰り返しになりますが、>>790 の「実行時にデータ内容に応じて分岐することを動的ディスパッチと言う」という定義は、一般的な定義とはまったく異なります >>790 の定義を採用する限りにおいてはその推論は正しいですが、そのためにはまずこの定義の出典および正確性を確認する必要があります このスレレベル高いね。 文系の俺にはちんぷんかんぷん。 雑魚はPHPでもしてるわ。 Rustはそのへんの話も明瞭で 「dyn」という予約語キーワードが出てきたものだけがvtableを使う動的ディスパッチとなるよ >>772 のRustコードは「dyn」が全く出てこないので、vtableを使う動的ディスパッチは一切無し、とわかる仕組み >>800 レベル高すぎてディスパッチが動的かどうかすらわからないからなwww 静的にディスパッチできたらいいのか、動的にディスパッチしたいのか。なんていうかgdgd ww >>800 ここは「朝から暇なおじさんの学習日記」だからある意味レベル高い。 >>801 を読んで思い出しましたが、 C++では動的ディスパッチが発生する条件のひとつとして、「virtual指定子付きメンバ関数の呼び出しである」という条件があります >>781 のコードにはvirtualがまったく存在しないため、動的ディスパッチが発生しないことが分かります >>789 のようにアセンブリでvtableの生成を確認するよりも、こちらのほうがより簡単な確認方法でした 誤った情報をお伝えしてしまい、大変申し訳ございませんでした ちゃんと検索したらなんかもうなんでもできそうなパターンマッチライブラリあった そうだよな、ないわけないよな https://github.com/BowenFu/matchit.cpp >>801 アホか? 静的ディスパッチとはコンパイル時に呼び出す関数が決定されることだよ match使ったら動的ディスパッチ >>807 Rustのenumのmatchはenumのインデックスで分岐してるだけ C++のvariantのvisitがvariantのインデックスで分岐してるだけなのと同じ どちらも動的ディスパッチはしていない 条件分岐は動的ディスパッチという 実行時ディスパッチと言った方が意味分かるかな? 動的ディスパッチというのは インデックスによる条件分岐 仮想関数によるディスパッチを含む広い概念です Rustも関数のオーバーロードくらいあるだろ? コンパイル段階でどの関数が呼ばれるかディスパッチされる これが静的ディスパッチ(の1つ) >>809 嘘つき 条件分岐つまりif文があれば動的ディスパッチだと主張するのか? 全てのプログラムが動的ディスパッチをしていることになるぞ >>812 >条件分岐つまりif文があれば動的ディスパッチだと主張するのか? その通り if文でどの関数を呼ぶか決めてるのであれば それは動的ディスパッチと言う これらはvtableを使うわけでもないし動的ディスパッチじゃないでしょ > Rustのenumのmatchはenumのインデックスで分岐してるだけ > C++のvariantのvisitがvariantのインデックスで分岐してるだけなのと同じ > どちらも動的ディスパッチはしていない >>814 >>772 >fn enum_pattern(shape: Shape) { > match shape { > Shape::Circle(r) => println!("半径{r}の円です"), > Shape::Rectangle(w, h) if w == h => println!("長さ{w}の正方形です"), > Shape::Rectangle(w, h) => println!("幅{w}高さ{h}の長方形です"), > x => println!("その他の図形{x:?}です"), > } >} ShapeがCircleなのかw == hであるRectangle(w, h)なのかそれ以外のRectangleなのか それともそれらに該当しないのかは実行時に決めているので 動的ディスパッチだよ 一方で >>785 >namespace Shape { > struct Circle {uint32_t r;}; > struct Rectangle {uint32_t w; uint32_t h;}; > struct Parallelogram {uint32_t ui0; uint32_t ui1;}; > template <typename T> void function (ostream &os, const T &p) {} > void function (ostream &os, const Circle &p) {} > void function (ostream &os, const Rectangle &p) {} >} 上記のどのfunctionが呼ばれるかは型に基づいてコンパイル時に選択される これが静的ディスパッチ じゃあ>>789 のC++コードは動的ディスパッチなの? vtableは無いしstd::visitでvariantのindex()値を見て実行時に分岐してるだけだから静的ディスパッチだと書かれているけど ID:wHEiYRW7は一つのIDを一貫して使ってるのに対し それにあほなレスつけて食って掛かってるほうはIDコロコロなんで 草も生えない毎度毎度のいつもの百年前から一生やってるrustスレ名物展開 >>817 Shapeが何かによって決めてるのは実行時なので 動的ディスパッチだよ ID:wHEiYRW7 >>809 がバカすぎる ID:7YA3tv0i氏の>>795 の説明を読もうぜ >>819 variantまで動的ディスパッチ扱いにするのはおかしいよ virtual関数をvtable経由で呼ぶのが動的ディスパッチじゃないかな >>795 >また、「実行時にデータ内容に応じて分岐することを動的ディスパッチと言う」という定義には明らかな問題があります >それは、この定義ではmatchやifなど通常の制御構造も動的ディスパッチに当てはまってしまうということです 何だそりゃ?w この説明の方が明らかにおかしい 他人に教えてもらったばっかりの内容で偉そうにしてんじゃねえ >>821 variantは良く知らんがShapeが実際には CircleかRectangleかParallelogramかを 実行時に判断しているので動的ディスパッチだよ >>816 との差は分かるでしょ? 分からんか? C++のvariantやRustのenumの値で条件分岐することを動的ディスパッチというのは無理があるんじゃないかな それはif文を使ったら動的ディスパッチと言ってるようなもの まだやってら どっちが来てもおっけーなようにtemplate<>が書けるのがC++のOOPだろ 無駄な議論 Rustもそんな感じだろ?w どっちも動的ディスパッチじゃなくね コンパイル後のenum_patternにCircleでもRectangleでもRectangleでもなく HogeAngleぶち込んでもディスパッチしてくれるのが動的じゃないの? >>825 >それはif文を使ったら動的ディスパッチと言ってるようなもの >>772 はShapeが何かはコンパイル時には決まりません >>789 もShapeが何かはコンパイル時には決まりません matchやifを使うということは実行時に決めていることを意味しているので動的ディスパッチです templateを駆使してコンパイル時に決定できる条件分岐を書けば 静的ディスパッチできるかもしれません 静的じゃないものは動的でいいと思うけど ディスパッチディスパッチ言ってんのは関数だけを前提にしたほうがいいんじゃない? match についてはもとの?ディスパッチ話から分離させたほうがいいかも? それとも元々matchの話なんだっけ? 最初の方読んでないけど 今まで関数かメソッド以外の文脈でディスパッチとか聞いたことなかったわ個人的に C++erは、書いたコードがディスパッチになるかは常に気にしてるからね(諸派あり そこを雑に書くと、ぶん殴られたりするからw だから、Rustの、書けばsafeになるってのは、欲しいんだなあ 生成コードに集中できる 百科事典で調べてみた >> https://www.weblio.jp/content/%E5%8B%95%E7%9A%84%E3%83%87%E3%82%A3%E3%82%B9%E3%83%91%E3%83%83%E3%83%81%E3%81%AE%E4%BE%8B >> C++では以下のように仮想関数を派生クラスにてオーバーライドすることで、 >> 実際に呼び出される関数の実体をオブジェクトの型に応じて実行時に選択することができる。 >> これを動的ディスパッチと呼ぶ。 この定義だとC++のvariant/visitでの分岐やRustのenum/matchでの分岐は動的ディスパッチではないな 一方でC++のvirtual関数やRustのdynトレイトは動的ディスパッチとなる >>832 >> https://www.weblio.jp/content/%E5%8B%95%E7%9A%84%E3%83%87%E3%82%A3%E3%82%B9%E3%83%91%E3%83%83%E3%83%81%E3%81%AE%E4%BE%8B >> C++では以下のように仮想関数を派生クラスにてオーバーライドすることで、 >> 実際に呼び出される関数の実体をオブジェクトの型に応じて実行時に選択することができる。 >> これを動的ディスパッチと呼ぶ。 これは動的ディスパッチの1つで 実行時に条件分岐して呼ぶ関数を決めるのも動的ディスパッチと呼ぶ 仮想関数によるディスパッチより動的ディスパッチの方が広い概念だよ 横からすみません Rustで日常茶飯事のこのパターンは動的ディスパッチですか? let output = match input { Some(input) => foo(input), None => Default::default(), }; >>827 何があれば「実践的」と言えるかの条件と、そもそも何のサンプルが欲しいのか、を明確にしないと誰も何も出せないよ >>772 はジャンプテーブルがないから動的ディスパッチじゃない >>834 それも動的ディスパッチじゃない >>833 が主張する『実行時に条件分岐して呼ぶ関数を決めるのも動的ディスパッチと呼ぶ』は無理があるんだよ >>838 俺はRust分からんのだけど これinputがSome(input)に適合するかしないかを 実行時に判断しているんやろ? だとしたら動的ディスパッチだよ C++のtemplateみたいに上記をコンパイル時に判断して 例えばSome(input)に適合するからDefault::default()を コールするコードが生成されないようなら静的ディスパッチ >>836 いま話題にしてる もとになった、パタンマッチングを上手く使ってる実例 なるほどこれはパタンマッチングがあってこそ、キマってるねっていうか というか>>789 の「静的ディスパッチ」もよく考えたら誤用だったわ https://en.wikipedia.org/wiki/Static_dispatch Rustならtrait bound付きgenerics内のtrait method呼び出しのことで良さそうだけど C++なら……ちょっとこのwikipediaの定義もなぜかオーバーロードに限定しててビミョ〜 これはRust以外の文脈では合意された定義無い気がする 静的か動的かはお互い認識にズレ無いと思うんよね でも「ディスパッチ」って言うとき 言語機能として用意されてる関数オーバーロードやvirtual使ったポリモとか 動的静的に関わらずまぁそこまではディスパッチなんだけど matchの結果やifの結果となってくるとそれって 言語の機能というより、言語の機能の機能ってことになってて 一気にぼんや〜りとしてくるんで一人一人にズレが生じるよね 1.どの振る舞いをするかがコンパイル時に選択される構造 2.どの振る舞いをするかが動的に選択される構造 3.振る舞いが追加されても動的に選択できる構造 パターンマッチは振る舞いの選択の話だから2 ポリモーフィズムを語る上での動的ディスパッチは3 2を動的ディスパッチと呼ぶかどうか >>839 実行時にならないとSomeかNoneかわからないからプログラムを組むんですよ コンパイル時点で決まっていたらプログラムを組む意味がありません そしてプログラムを組めば必ずどこかに条件分岐があります それを動的ディスパッチとは言わないと思うんです >>840 C++?Rust?どっち? てかやっぱり基準が曖昧だけど、何かしら有名OSSのソースでも出せばいいの? >>841 >This contrasts with dynamic dispatch, which is based on runtime information > (such as vtable pointers and other forms of run time type information). そこにdynamic dispatchを説明する一文があって2行目()内の and以下に書かれているのがまさにifやmatchで評価していること >>845 明らかにそいつは周回遅れのド素人なので アナタ以外のみんなは単に無視してるようですよw 時間の無駄はおすすめしません >>846 type informationとありますね SomeもNoneも型ではありませんから >>834 は動的ディスパッチではないということになります Rustのenumによるmatchでの分岐は動的ディスパッチではないということでよろしいでしょうか? >>845 RustのOSSで >>847 よく言われるよ >>844 条件により振る舞いを変えること一般をディスパッチと呼ぶ 例えば>>785 でmain内でfunction (cout, circle);とfunction (cout, parallelogram);では 呼ばれる関数が変わり振る舞いが変わるんだけど これはコンパイル時に選択されます これを静的ディスパッチと呼びます 一方で834のmatchによる分岐は静的には決まらないので 静的ディスパッチに対して動的ディスパッチと呼びます >>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だったり 何に対しても使える用語だから 区別できてない人もいるんだろう ■ このスレッドは過去ログ倉庫に格納されています
read.cgi ver 07.5.5 2024/06/08 Walang Kapalit ★ | Donguri System Team 5ちゃんねる