X



結局C++とRustってどっちが良いの?

■ このスレッドは過去ログ倉庫に格納されています
0001デフォルトの名無しさん
垢版 |
2023/02/25(土) 09:49:46.74ID:VRyB88xR
C++の色々配慮してめんどくさい感じは好きだけど、実務になったらメモリ安全性とか考えて今後Rustに変わっていくんかな?
0699デフォルトの名無しさん
垢版 |
2023/03/29(水) 11:49:15.76ID:KmrCY6Bh
>>678
これってダウンキャスト入ってるから危険なこともできそう
相当するコードはRustではコンパイル通らない?
#include <iostream>
#define DOUT(arg) std::cout << #arg": " << arg << std::endl
template<typename T> struct AddN {
void add2() {
static_cast<T*>(this)->add1();
static_cast<T*>(this)->add1();
}
};
struct Foo : AddN<Foo> {
int x;
Foo(int i) : x(i) {}
void add1() {
this->x++;
}
};
struct Bar : AddN<Foo> {
double y;
Bar(double i) : y(i) {}
void add1() {
this->y+=0.1;
}
};
int main () {
Foo foo (1); Bar bar (0.1);
DOUT (foo.x); DOUT (bar.y);
foo.add1 (); bar.add1 ();
DOUT (foo.x); DOUT (bar.y);
return 0;
}
0700デフォルトの名無しさん
垢版 |
2023/03/29(水) 11:51:44.76ID:KmrCY6Bh
実行したら以下のようになった
$ ./a.out
foo.x: 1
bar.y: 0.1
foo.x: 2
bar.y: 0.2
最後のbar.yは1.1になると思ってたんだがはて?
0701デフォルトの名無しさん
垢版 |
2023/03/29(水) 12:42:03.29ID:KmrCY6Bh
そもそもBarはFooを継承してないんだから
ダウンキャストのところでコンパイルエラー出て良いようなもんだけど
何で通すんだろ? templateだとチェックを緩和してるのかな?
あるいはコンパイラのバグかな?
$ g++ --version
g++ (Debian 10.2.1-6) 10.2.1 20210110
0702デフォルトの名無しさん
垢版 |
2023/03/29(水) 12:43:14.11ID:KmrCY6Bh
-ダウンキャストのところでコンパイルエラー出て良いようなもんだけど
+static_cast<T*>(this)->add1();のところでコンパイルエラー出て良いようなもんだけど
0703デフォルトの名無しさん
垢版 |
2023/03/29(水) 12:55:36.31ID:jlgG+N1i
最近のC++はよく分からんけどその例だとadd2使わないと多分変なことにならない
doubleをint扱いして1足しても1/(2^53)(←不正確、指数部による)くらいしか変動しないのかな
FooもBarもAddN継承してるからstatic_castでコンパイルエラーは出ないはず

Rustはクラス継承がないからstatic_castとの正確な比較はできない
traitで似たようなコード書くときはSelfキーワードで自分の型を指すからダウンキャスト必要ないし
敢えてstatic_castと対応させるならtransmuteだろうけどunsafe付きの関数だから危険でもコンパイルは通せる
(unsafeを使う範囲の安全性保証はプログラマの責任)
0704デフォルトの名無しさん
垢版 |
2023/03/29(水) 13:10:19.46ID:KmrCY6Bh
>>703
>最近のC++はよく分からんけどその例だとadd2使わないと多分変なことにならない
あーごめんごめん!興味があったのはadd2を呼んだときの挙動だった
- foo.add1 (); bar.add1 ();
+ foo.add2 (); bar.add2 ();
$ ./test
foo.x: 1
bar.y: 0.1
foo.x: 3
bar.y: 0.1 <- 鼻から悪魔

>FooもBarもAddN継承してるからstatic_castでコンパイルエラーは出ないはず
なるほどキャストしているthisはAddN<Foo>*だから
Foo*にもBar*にもダウンキャストできるってことね
ありがとう
0705デフォルトの名無しさん
垢版 |
2023/03/29(水) 13:47:10.36ID:KmrCY6Bh
正当?なC++的にはdynamic_castすべきなんじゃなかろうかって思うんだよね
でそれはvtable介してadd1にアクセスするのと変わらない
プログラマの責任でstatic_castして効率化する
ってテクニックは俺は割と好きだけども
0706デフォルトの名無しさん
垢版 |
2023/03/29(水) 14:18:14.91ID:JN59fMMe
>>703
transmuteはダウンキャストではなく任意の型同士の強引な型変換(読み替え)だから当然unsafe
一方でダウンキャストは親から子、基底から派生、抽象から具体への変換を指す
Rustの場合は抽象的なトレイトから具体的な型への変換がダウンキャストとなる

Rustは基本的には静的ポリモーフィズムで
コンパイル時点で各具体的な型のコードへ安全に置き換わるモノモーフィズムなので
C++のstatic_castのような危険のあるダウンキャストを必要としないが正解

Rustでもdyn Traitを用いた場合のみ動的ポリモーフィズムとなり
C++のdynamic_castと同様に実行時ダウンキャストがdowncast()/downcast_ref()/downcast_mut()で可能だが
C++とは異なりRustはNull安全でダウンキャストできる
0709デフォルトの名無しさん
垢版 |
2023/03/29(水) 15:30:35.32ID:jlgG+N1i
動的検査のコストよりもキャストに失敗した時の分岐処理のせいで最適化が阻害されるのを問題視してる感じ
かといって分岐しないなら動的検査の意味ないし
0710デフォルトの名無しさん
垢版 |
2023/03/29(水) 15:35:36.31ID:jd4hHaC+
>>706
ダウンキャストの根本的な問題点を理解してないね
静的か動的かUBかどうかは副次的な問題点に過ぎない
0711デフォルトの名無しさん
垢版 |
2023/03/29(水) 15:40:07.88ID:R/bWJVR7
Rustのポインタ(参照)のNull安全ってすごく上手い仕組みだな
C++のdynamic_castもRustのdowncast_refも生成コードはどちらもダウンキャスト成功時はそのままポインタを返して失敗時は0を返す点で効率も同じだけど
Rustでは返す型としてはそれをポインタで直接に表さずにOption<&T>を返すと表現させて
成功時はOption::Some(&T)を返して失敗時の0はOption::Noneとして返すため
プログラムコード上はNoneかSomeか生成コードでは0か否かをチェックせずには使えないわけだ

C++でのNullポインタか否かのチェック忘れを静的な型チェックで防止できるってことは
もしかしてC++でもdynamic_castやその他のNullポインタを返すライブラリ全てをstd::optionalを返すように変更すればNull安全になるんじゃないか?
0712デフォルトの名無しさん
垢版 |
2023/03/29(水) 15:45:49.19ID:RttupHdJ
>>710はいつものデタラメ言いがかり君に似てる
闇雲に否定して別の問題点があると主張しつつ
その問題点を述べることは一切ないので書き込みの中身がない
0713デフォルトの名無しさん
垢版 |
2023/03/29(水) 17:50:54.05ID:aWl/4JyA
>>711
デフォルトmoveの導入は無理だと思ってるくせにNull安全は導入できると思ってるのかw
オツム弱っww
0714デフォルトの名無しさん
垢版 |
2023/03/29(水) 18:18:44.67ID:eKurmGUm
たぶん人違いじゃないかな?
dynamic_castの返り値を確認しないやつは
流石におらんと思うよ
静的に確認してくれても全く嬉しくない
0716デフォルトの名無しさん
垢版 |
2023/03/29(水) 18:50:51.61ID:3DtieHtv
ヌルポインタが返る全ての関数についてそうしないとヌル安全にならない
ヌルを使ってはダメ
0717デフォルトの名無しさん
垢版 |
2023/03/29(水) 19:05:30.65ID:KmrCY6Bh
それは当然だよ
C++では指し示した先にインスタンスがあるかどうか
分からんときにのみポインタを使う
確実にあるときは参照を使うのが流儀
ポインタが使われるところではnullptrのチェックを行う
この流儀の部分を守らないスカタンが問題なんだな
Cに参照がないので上記流儀が守られないことも問題
0718デフォルトの名無しさん
垢版 |
2023/03/29(水) 19:30:08.82ID:ap6Xt56V
>>704
なぜそのC++のプログラムは正しく動かいていないの?
bar.yはadd2()で0.2足されて0.1から0.3にならないといけないのに0.1のままになってる
>>699のソースコードを見ても正しく動かない原因がよくわからない
0720デフォルトの名無しさん
垢版 |
2023/03/29(水) 19:41:07.31ID:ap6Xt56V
>>719
add2()としてBarの+0.2が使われずFooの+2か使われるということ?
bar.yが2.1になっていないのはなぜ?
0721デフォルトの名無しさん
垢版 |
2023/03/29(水) 19:53:07.69ID:KmrCY6Bh
templateを展開すると
void Add <Foo>::add2() {
static_cast<Foo*>(this)->add1();
static_cast<Foo*>(this)->add1();
}
thisはBarの基底AddN<Foo>*のポインタ
これをBarと無関係のFoo*にキャストしたら動作は不定
0722デフォルトの名無しさん
垢版 |
2023/03/29(水) 20:09:37.10ID:ap6Xt56V
なるほど
浮動小数点に対してそれを整数と見て+2してしまっているのかな
本来はコンパイル段階でエラーにしないとやばそうだ
今回はっきり動いていないとわかるケースだからいいけど何となく動いてしまってるケースがあると恐ろしい
0723デフォルトの名無しさん
垢版 |
2023/03/29(水) 20:11:29.28ID:KmrCY6Bh
正当?なC++的にはdynamic_castすべきだと思うんだよね
template<typename T> struct AddN {
void add2() {
dynamic_cast<T&>(*this).add1();
dynamic_cast<T&>(*this).add1();
}
virtual ~AddN () {};
};
0727デフォルトの名無しさん
垢版 |
2023/03/29(水) 20:50:49.78ID:ij9aGzzi
doubleのビット列をintとして扱ってインクリメントしてるから結果がおかしいんだろ
なぜコンパイラは型不一致エラーを出せないんだ?
0728デフォルトの名無しさん
垢版 |
2023/03/29(水) 21:21:00.23ID:iEVzPlea
問題があれば何でもコンパイル時点でエラーを出してくれるRustを使おう
実行デバッグが激減して開発効率も高い
0731デフォルトの名無しさん
垢版 |
2023/03/29(水) 23:01:50.75ID:UIOCT5jB
ライブラリが一個もない状態から基本的なライブラリを作るためにunsafeが必要という話だったら
有限個のバイナリファイルが正しく出力されればいいだけなので
ソースコードをチェックしなくても出力をチェックすればいいのでは?
0733デフォルトの名無しさん
垢版 |
2023/03/30(木) 06:54:54.18ID:uZvbGS3c
そういえばJavaが全然話題にもならないが言語のヒエラルキーって

C++ 最強カミソリ
剃り残しナシ

Rust 安全カミソリ
キレテナーィ なまくら

C# イケてるが
GCがあるからダメぽ

Java 論外
ヌルポとGCがあるからダメぽ

こんな感じ?
0735デフォルトの名無しさん
垢版 |
2023/03/30(木) 07:25:50.11ID:xjlzONIR
俺にとってのC++は、日本語だよ 物心ついたときには、C++だったんだ
氏ぬまで忘れないと思う だからある意味最強、そんな奴が結構多いんだと思う

「ちゃんと話せ」って躾けられたのも、良し悪し
0737デフォルトの名無しさん
垢版 |
2023/03/30(木) 07:42:11.73ID:w91B/KcY
C++が出来なくてRustが出来ることってある?
0739デフォルトの名無しさん
垢版 |
2023/03/30(木) 08:01:00.44ID:Lly0YXlC
>>737
C++はできないことが多すぎる
このスレに出てきた話だけでも
代数的データ型
パターンマッチング
各種null安全
データ競合安全
メモリ安全
など多数
0740デフォルトの名無しさん
垢版 |
2023/03/30(木) 08:18:36.82ID:PJ70lfxq
プリミティブはいろいろ備わってるから、やってできなくはないんだろうけど、
強制する方法がないから、ちっとも普及しないんだよね
0741デフォルトの名無しさん
垢版 |
2023/03/30(木) 08:28:14.61ID:Lly0YXlC
>>740
C++はそのプリミティブを多数欠いている
まさか代数的データ型をunionで頑張ればできると主張するのか?
パターンマッチングは構文だからC++には無理
データ競合を静的に検知する方法もない
0742デフォルトの名無しさん
垢版 |
2023/03/30(木) 08:32:28.84ID:PJ70lfxq
C/C++には昔から、「なければgenerateすればいいじゃん」っていう文化がある
パターンマッチングは、いまどきIDEが記述支援するんだから、やってできなくはない
データ競合やらは、「そういう」スマポを導入すればいい

でもね、みんな使わないんだわ 使われないものは、ないものとして詰られても仕方ない

あ、Cとおんなじように、入れ子になった構造体をささっと書きたいとかは思うね
もうできるようになったっけ?
0744デフォルトの名無しさん
垢版 |
2023/03/30(木) 09:18:55.32ID:PJ70lfxq
…いやまてよ、パターンマッチングって、エラー等検出のことだと思ってたけど、
パターンマッチング Rust でぐぐったら全然違うものが出てきたぜ その節は撤回 ちょっと読んでみる
0745デフォルトの名無しさん
垢版 |
2023/03/30(木) 10:37:10.30ID:z+Rtq9PG
0748デフォルトの名無しさん
垢版 |
2023/03/30(木) 10:58:13.17ID:xP+9HiJo
パターンマッチングはC++23に入れようとしたがRustと比べて機能も弱すぎて失敗している
Rustのパターンマッチングはこんな感じで記述性や可読性を向上させている
fn slice_pattern(slice: &[(i32, i32)]) {
match slice {
[] => println!("空です"),
[(a, b)] => println!("要素は1つで({a},{b})です"),
[_, (123, b), ..] => println!("2つ目の前者が123なものは(123,{b})です"),
[.., next_last, _] => println!("その他の最後から2つ目の要素は{next_last:?}です"),
}
}
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:?}です"),
}
}
fn struct_pattern() {
let a = Foo { bar: 123, baz: 456, qux: 789 };
let b = Foo { baz: 555, ..a };
for Foo { bar, baz, qux } in &[a, b] {
println!("Foo: bar={bar}, baz={baz}, qux={qux}");
}
}
fn range_pattern(c: char) {
match c {
'0'..='9' => println!("数字({c})です"),
'a'..='z' | 'A'..='Z' => println!("アルファベット({c})です"),
_ => println!("その他の文字({c})です"),
}
}
0749デフォルトの名無しさん
垢版 |
2023/03/30(木) 11:05:35.09ID:wHEiYRW7
C++はユーザが多いので標準でなくてもライブラリがあるからね
Rustはユーザが少ないので標準で用意しとく必要がある
パタンマッチングは言語の話だけども
0751デフォルトの名無しさん
垢版 |
2023/03/30(木) 11:14:15.70ID:xP+9HiJo
>>747
C++のstd::variantは全体の型名を命名できない
各要素に対して専用の型を用意しなければならない
扱いづらいなど欠陥品

例えば>>748のShapeの定義例は
enum Shape {
Circle(u32),
Rectangle(u32, u32),
Parallelogram(u32, u32),
}
これだけで済む
さらに型Shapeに対して様々なメソッドを実装できる
C++ではそれぞれ困難と不可能

>>749
言語がサポートしないとライブラリでは無理
0752デフォルトの名無しさん
垢版 |
2023/03/30(木) 11:14:43.48ID:PJ70lfxq
一発目から GET / HTTP/1.1 じゃないものが来てるかもよ、buffer 表示させてみては
0754デフォルトの名無しさん
垢版 |
2023/03/30(木) 11:32:57.91ID:xP+9HiJo
>>753
読んだけどそれでは無理
こちらはパターンマッチングのRustのコード例を>>748に出した
C++でも可能だと主張するならばそれぞれの実現コードをまず出すべき
0755デフォルトの名無しさん
垢版 |
2023/03/30(木) 11:39:46.03ID:PJ70lfxq
パターンマッチングの件、5分くらい読んできた
そういう風に書きたいっていうニーズがあるんだな、表現力を誇るC++でこれが書けないのは確かに手落ちw

この型はあれでもこれでもあるっていうの、あんまり扱ってこなかったけど、
上手く書けば便利になるかもね ただし、ゼロサンクでね
0757デフォルトの名無しさん
垢版 |
2023/03/30(木) 11:46:33.32ID:7YA3tv0i
>>754
「無理」とだけ言われても何も分からないので具体的にお願いします
それとも記事を読んだうえでも、無理な点の指摘は>>751ですべてだということですか
例を読んでいれば「各要素に対して専用の型を用意しなければならない」は嘘だとすぐ分かるはずですが
0758デフォルトの名無しさん
垢版 |
2023/03/30(木) 11:47:15.19ID:xP+9HiJo
>>755
Rustは>>748の各パターンマッチング例をオーバーヘッド無しで処理してくれる
使わずに手動でダラダラと書ける分もパターンマッチング記述の方が最適化が良いかもしれん
0759デフォルトの名無しさん
垢版 |
2023/03/30(木) 11:49:39.34ID:xP+9HiJo
>>757
具体的に>>748にRustのパターンマッチングの各例のコードを書きました
次はC++でも可能だと主張するあなたが対応するC++のコードを出す番です
0760デフォルトの名無しさん
垢版 |
2023/03/30(木) 11:58:04.66ID:7YA3tv0i
>>759
あなたの要求に答えるために質問だけさせてください
明確にしてほしいのは「何が無理なのか」の「何」の部分です
よろしくおねがいします
0761デフォルトの名無しさん
垢版 |
2023/03/30(木) 11:58:20.56ID:PJ70lfxq
教科書的サンプルとは別に、実践的なサンプルが見たいぞ
必要だから入った仕様だろう、手ごろにどっかあるはずだ お勧めのやつをたのむ
0762デフォルトの名無しさん
垢版 |
2023/03/30(木) 11:59:10.65ID:wHEiYRW7
>>751
>>749>パタンマッチングは言語の話だけども

>例えば>>748のShapeの定義例は
>enum Shape {
> Circle(u32),
> Rectangle(u32, u32),
> Parallelogram(u32, u32),
>}
>これだけで済む
>さらに型Shapeに対して様々なメソッドを実装できる
>C++ではそれぞれ困難と不可能
横レスだけども
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);
// void function (ostream &os, const Parallelogram &p);
}
0770デフォルトの名無しさん
垢版 |
2023/03/30(木) 12:47:49.82ID:xP+9HiJo
>>760
Rustはパターンマッチングがあるため>>748のようにシンプルに記述ができて可読性にも優れている
あなたはC++でも代わりの手段で表現することが可能だと主張した
それが無理ではないことをRustコードの各々に対応する具体的なC++のコードとして示してほしい
0771デフォルトの名無しさん
垢版 |
2023/03/30(木) 12:56:56.84ID:wHEiYRW7
パターンマッチングは便利だけども必須じゃないよね
所有権システムと違って後方互換性が犠牲になることはないので
そのうちC++に入るよ
0772デフォルトの名無しさん
垢版 |
2023/03/30(木) 13:16:45.82ID:tVTq+AM2
>>769
パターンマッチング>>748の2番目の例の話だからShapeは関数に渡ってくる型じゃないとまずい
単体で動くコードで比較すればはっきりすると思うのでC++版を書いて。以下はRust版

// ここは再掲
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:?}です"),
}
}
#[derive(Debug)]
enum Shape {
Circle(u32),
Rectangle(u32, u32),
Parallelogram(u32, u32),
}

fn main() {
enum_pattern(Shape::Circle(100));
enum_pattern(Shape::Rectangle(200, 300));
enum_pattern(Shape::Rectangle(567, 567));
enum_pattern(Shape::Parallelogram(789, 456));
}

// 実行結果
半径100の円です
幅200高さ300の長方形です
長さ567の正方形です
その他の図形Parallelogram(789, 456)です
0775デフォルトの名無しさん
垢版 |
2023/03/30(木) 13:31:12.50ID:tVTq+AM2
>>773
Shape型が渡ってきてその処理をしてるからだよね
とりあえずC++の動くコードを出してみたら?
0776デフォルトの名無しさん
垢版 |
2023/03/30(木) 13:32:51.26ID:wHEiYRW7
>>775
Shape型を引数で取る必要があるならC++では
Shapeを基底として継承させるよ
もちろん静的ディスパッチはできない
0777デフォルトの名無しさん
垢版 |
2023/03/30(木) 13:35:28.76ID:wHEiYRW7
図形は典型的なオブジェクト指向の例題だから
enumを使う例としては適切ではないんじゃないかな?
Rustをよく知らん俺からしたらピンとこないよ
0778デフォルトの名無しさん
垢版 |
2023/03/30(木) 13:39:12.89ID:8gDdaVz7
>>774
ディスパッチは静的には不可能で動的にしか行われないでしょ
静的に可能なのはモノモーフィゼイションだけど今回の例では適用できませんね
いずれにしてもC++で可能だと言うコードを示してみたら?
0780デフォルトの名無しさん
垢版 |
2023/03/30(木) 13:41:01.47ID:wHEiYRW7
>>778
>ディスパッチは静的には不可能で動的にしか行われないでしょ
いいえ>>762は静的に行われる

>いずれにしてもC++で可能だと言うコードを示してみたら?
>>762に示した
0782デフォルトの名無しさん
垢版 |
2023/03/30(木) 13:52:02.49ID:tVTq+AM2
>>780
動くコードじゃないと意味がないのでmain()付きの動くコードを示そうよ
Rust版は>>772

>>781
パターンマッチングを全く行なっていないじゃん
例えば分かりやすくこの項目を増やすとして
Shape::Rectangle(100, h) => println!("幅100で高さ{h}の長方形です"),
これはC++でif (w == 100)のコードになるわけだよね
それはパターンマッチングとは言わないよ
0783デフォルトの名無しさん
垢版 |
2023/03/30(木) 14:01:06.19ID:7YA3tv0i
>>782
enumのバリアント判定に相当するパターンマッチを行っていますので、全く行っていないという指摘は正しくありません
また、>>748のenum_patternにShape::Rectangle(100, h)にマッチするコードは含まれておらず、あなたの当初の要求に含まれていないものです
新しい要求を後から追加して批判するのは、誠実な態度とは言えません
このようなことが無いように、「何が無理か」を明確にするよう確認したつもりでした
今後はこうしたことが無いように、事前よく確認することをお願い申し上げます

また値によるマッチについてですが、同様の考えで似たライブラリを実装された方を見つけました
こちらは値によるマッチに拡張したライブラリを実装されているようです
https://qiita.com/Naotonosato/items/a1e710de2b78346146d1
0785デフォルトの名無しさん
垢版 |
2023/03/30(木) 14:14:54.28ID:wHEiYRW7
>>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;
}
0786デフォルトの名無しさん
垢版 |
2023/03/30(木) 14:47:32.70ID:Evbafc70
静的ではなくて動的ディスパッチだろ
このように次々と何が来るかわからないリストが渡ってきた場合

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]);
}
0788デフォルトの名無しさん
垢版 |
2023/03/30(木) 15:04:41.33ID:PJ70lfxq
もうちょっと調べてたが、C++にもinspectってのが来そうみたいじゃん
パタンマッチングって、こんなもんが流行ってるのね、また一つ取り残されてたぜ
0789デフォルトの名無しさん
垢版 |
2023/03/30(木) 15:04:46.89ID:7YA3tv0i
>>786
いいえ、これは静的ディスパッチです
簡単に確認する方法として、生成されたアセンブリ中のvtableを確認する方法があります:
https://godbolt.org/z/1W7jGnWEd

"vtable for std::bad_variant_access:"が唯一のvtableであり、Circleなどのためのvtableはありません
このことから、動的ディスパッチは発生しないことが分かります
0790デフォルトの名無しさん
垢版 |
2023/03/30(木) 15:09:53.24ID:Evbafc70
>>789
おいおい
vtable使うことだけが動的ディスパッチだと思いこんでいるのか?
実行時にデータ内容に応じて分岐することを動的ディスパッチと言う
>>786はもちろん動的ディスパッチをしている
次に何が来るかはコンパイル時点で決まらないため静的に決定は不可能だ
0791デフォルトの名無しさん
垢版 |
2023/03/30(木) 15:10:42.88ID:wHEiYRW7
>>788
昔はなかなか規格としてまとまらなかったが最近のC++はどうした?
俺もboostに入ってたやつくらいしか追えていない
0795デフォルトの名無しさん
垢版 |
2023/03/30(木) 15:29:45.34ID:7YA3tv0i
>>790
いいえ
動的ディスパッチとは、多態メソッドの呼び出し式を実行するときに、具体型に応じて実際に呼ばれる関数が振り分けられることを言います
https://en.wikipedia.org/wiki/Dynamic_dispatch

動的ディスパッチはしばしばパフォーマンスの低下をもたらすと言われますが、その最大の理由は、
選択される各関数ポインタを一度メモリから(vtableから)読み出し、それをcallする必要があることです
動的ディスパッチをどう定義するかはさておき、vtableが無い>>789ではこのパフォーマンス低下の懸念が無いことが分かります

また、「実行時にデータ内容に応じて分岐することを動的ディスパッチと言う」という定義には明らかな問題があります
それは、この定義ではmatchやifなど通常の制御構造も動的ディスパッチに当てはまってしまうということです
これは、この定義が一般的な定義から大きく逸脱していることをよく象徴的に表わしています
少なくとも「データ内容」は「型」に置き換える必要があることが分かるでしょう
0796デフォルトの名無しさん
垢版 |
2023/03/30(木) 15:38:08.65ID:RiLc+pIf
>>789
それは動的ディスパッチだよ
C++のstd::visitはstd::variantのindex()の値で実行時に分岐してる
だから>>786のような実行時になるまで何が来るか不明な場合にも対応できる
0797デフォルトの名無しさん
垢版 |
2023/03/30(木) 15:39:00.20ID:PJ70lfxq
>>791
inspectは、godboltでclangのexperimentalを遊べるようになってた
型に対しては、もうちょっとまだみたい、error: expected expression って言われた

ラムダみたいに、みんなが欲しがるものはそれでもわりと早いんだよね
一応入れとくか…みたいのは、いつまでたっても入らないw

ところで、godboltに、-Wlifetime ってのがみえたけど…これってもしかして
0798デフォルトの名無しさん
垢版 |
2023/03/30(木) 15:59:56.98ID:QNJ4BihP
C++の仕様を変えようという時に国語辞典の変更を許さないのはタイパ最悪だな
C++の仕様変更を許さない、とすれば秒速で終わる
0799デフォルトの名無しさん
垢版 |
2023/03/30(木) 16:08:41.30ID:7YA3tv0i
>>796
いいえ、これは動的ディスパッチではありません
「実行時になるまで何が来るか不明な場合にも対応できる」ことは、それが動的ディスパッチであることの証明にはなりません
繰り返しになりますが、>>790の「実行時にデータ内容に応じて分岐することを動的ディスパッチと言う」という定義は、一般的な定義とはまったく異なります
>>790の定義を採用する限りにおいてはその推論は正しいですが、そのためにはまずこの定義の出典および正確性を確認する必要があります
■ このスレッドは過去ログ倉庫に格納されています

ニューススポーツなんでも実況