C++相談室 part162
レス数が1000を超えています。これ以上書き込みはできません。
!extend:checked:vvvvv:1000:512
!extend:checked:vvvvv:1000:512
↑同じ内容を3行貼り付けること
次スレは>>980が立てること
無理なら細かく安価指定
※前スレ
C++相談室 part161
https://mevius.5ch.net/test/read.cgi/tech/1653135809/
VIPQ2_EXTDAT: checked:vvvvv:1000:512:: EXT was configured 寿限無寿限無五劫の擦り切れ海砂利水魚の水行末雲来末風来末食う寝る処に住む処藪ら柑子の藪柑子パイポパイポ パイポのシューリンガンシューリンガンのグーリンダイグーリンダイのポンポコピーのポンポコナーの長久命の長助 template <template<class...> class T>
struct is_map : std::false_type { };
template<> struct is_map<std::map> : std::true_type { };
template<> struct is_map<std::multimap> : std::true_type { };
template<> struct is_map<std::unordered_map> : std::true_type { };
template<> struct is_map<std::unordered_multimap> : std::true_type { };
template <template<class...> class T>
concept map_t = is_map<T>::value;
template <template<class...> map_t MAP, class... ARGS> //C3339
void test(MAP<ARGS...>&&) {}
うーん、困った
どうしよう。。。 あ、そっか
㌧x
一応、報告
template <template<class...> class MAP, class... ARGS> requires map_t<MAP> //OK
void test(MAP<ARGS...>&&) {} AssociativeContainer要件のコンセプトは標準ライブラリには無いんだな
規格上定義してるrequirementは一通り作っとけばいいのに >>8
でも文法的コンパイラ的には許されている
100段くらい重ねて大丈夫なんじゃなかろうか >>10
コンパイラが無限のリソースを使えるわけじゃないから制限があってもいいし、
わかっている制限は文書化するべきということになっている。
https://timsong-cpp.github.io/cppwp/n3337/implimits
言語仕様の側でもどの程度まで処理すべきかという最低限の数値は与えていて
この場合だと
Recursively nested template instantiations [1024].
ってのが当てはまる。
あくまでもガイドラインなのでこれ以下に制限された処理系がないとは言えないんだけど、
1024 が提示されているところで 100 やそこらに制限するような処理系はたぶんあんまりないとは期待できると思う。 そんなん言い出したら自動変数は合計何バイトまでとか
しょーもないことを規格票に書くハメにならないか? GCCとClangの -ftemplate-depth-?? の話? つーかよ
俺5だけど、あの程度のことで
8みたいなこと言われたのずっこけてる
別に無駄に複雑化はしてないし裏技も使ってない
当たり前の書き方で目的を素直に書いてるだけなのに
一次テンプレートと特殊化でis_系のクエリーを作って
それでコンセプト作って使おうとしただけだぜ?
何があかんの?
テンプレートテンプレート仮引数がわからんだけじゃないのかって邪推しちまいそう 話は綺麗に終わってるのに
発展的に関連した話題を振るのならともかく
何で>>8みたいなコメントをいちいち付けるのか俺も理解不能 >>14
そうそう昔はこれを付けないで17超えるとエラーが出てた
-ftemplate-depth-100 くらいで使ってたけど
いまはデフォルトで1024になってるのね 制限はあくまでも「深さ」であって「回数」ではないので上手いこと変形するのも技の内だったんだよな……。
遊びでやるならきつめの制限も楽しいんだけどね。 自動的に解釈されるテンプレート引数で
値渡しじゃなく参照渡しと解釈させる方法ってありますかね? 明示的な型変換が可能か調べる方法ってありますか?
暗黙的ならis_convertibleが使えるのですが…
std::is_convertible<std::shared_ptr<void>, bool>::value; // trueになってほしい >>23
std::is_constructible<bool, std::shared_ptr<void>>::value
ありがとうございました。 質問です
マネージドとかアンマネージドとかMSの呪いですか? プログラミング言語 C++ [第四版]
BJARNE STROUSTRUP, 柴田望洋 訳
「第四章 C++を探検しよう:コンテナとアルゴリズム」のp.102-103
に以下の様なコードが有るのですが、phone_book = の右側の初期化子(?)
の部分をコンパイラ内部でどのように翻訳(解釈)していくのかの厳密な詳細が
分かりませんので、どなたか教えてもらえませんか。
struct Entry {
string name;
int number;
};
vector<Entty> phone_book = {
{"David Hyme",123456},
{"Karl Popper",234567},
{"Bertrand Arthur William Russell",2345678}
};
前提として、クラステンプレート vector<T> には、以下のような
「初期化子並びコンストラクタ」があることとします。
template <class T, class Alloc = allocator<T>>
class vector {
・・・
// 初期化子並びコンストラクタ :
vector( std::initializer_list<T> a );
・・・
}
ここで問題となるのは、以下のどちらの方法で解釈されているかということです。
[続く] >>28
[続き]
(1) {・・・}を翻訳した後に、コンストラクタを探す。
phone_book = の右側の部分は、コンパイラ内部で、いったん
std::initializer_list<UUU>型のオブジェクトに直される
(なお、UUU がどんな型かは不明)。
vector<Entry>クラスの中にたまたま「初期化子並びコンストラクタ」
vector( std::initializer_list<Entry> )を見つけて
initializer_list<UUU>をinitializer_list<Entry>に変換してから、
vector( std::initializer_list<Entry> )に渡す。
(2) コンストラクタを見つけた後に、{・・・}を翻訳する。
vector<Entty>クラスの中にコンストラクタを探して、
vector( std::initializer_list<Entry> ) があることを発見。
このコンストラクタの引数が、std::initializer_list<Entry>であることから、
phone_book = の右側の部分を、std::initializer_list<Entry> だと
思って、コンパイル(意味論的に解釈)する。
# 推定ですが、(1)だと上手く行かない気がします。
[続く] >>29
[続き]
[自分なりに調べたこと]
[A] p.293. 11.3 「並び」によれば、
{}構文は、名前付き変数を初期化する(§6.3.5.2)だけでなく、
(すべてではないものの)多くの箇所で式として利用できる。その構文は、
以下の二種類だ:
[1] T{...}:型で修飾された形式。"T型のオブジェクトを作成してT{...}で初期化
する"ことを意味する。§11.3.2。
[2] {...}: 型で修飾されていない形式。利用している文脈に基いて型を
決定できる必要がある。§11.3.3。
# auto以外では{}内の要素の型は推論に利用「されない」」らしい。p.297
[B] p.327によると、
「{}で囲んだ並びは、以下のものに対する引数として利用できる:
[1] std::initializer_list<T>型。並びの中の要素の値は、
暗黙理にTへと変換される。
[2] 並びの中に与えられている値で初期化可能な型
[3] Tの配列への参照。並びの中の要素の値は、暗黙裡にTへと変換される。 大体わかってそうだけど
{…}をinitializer_list<Entry>として解釈しようと試みる→中身の{"David Hyme",123456}とかをEntry型に暗黙変換しようと試みる→全部変換できれば成功
Entryがexplicit Entry(string, int);を持ってると暗黙変換できなくて失敗するようになる >>31
vector<T>クラスのコンストラクタに、initializer_list<T> 以外の引数を
持つものが存在していた場合、どういう優先順位でコンストラクタが選ばれて
いくのでしょうか。
コンパイラは、最初に初期化子の {・・・} の部分のカンマで区切られた中身の
個数を数えてから、その個数によってどのコンストラクタを選ぶかを決めますか? >>32
仮にそうだとすると、コンパイラの内部では、
1. vector<Entty> phone_book の宣言の型である vector<Entty>を把握。
2. = の右側の初期化子の部分の{}の中の個数など大まかな特徴を掴む。
3. 2の特徴に基いて最適なvector<Entry>のコンストラクタを探す。
4. = の右側の部分を3.のコンストラクタに基いて解釈/変換する。
という少なくとも4段階の工程を得ていることになりそうですが、随分と
特殊な解釈の仕方ですね。
通常の式ならば、このように「いったりきたり」はしないものですが。 そこは通常のオーバーロード解決と同じだけど何が気に食わないの?
f(int)とf(int,int)があってf(1,2)を解決するときに「先に引数が2個あることをチェックするなんてインチキだ!」って発狂されても >>34
しかし、その場合、どの関数を呼び出すかが決定されてから後に、パラメータ(実引数)
の意味解釈は変化せず、実引数の解釈は同じで、必要あらば関数の仮引数へとcastされるだけです。
ところが、今回の初期化子の場合は、実引数の大体の様子が調査された後に、
どのコンストラクタを使うかが決定。コンストラクタが決定された後に、実引数の
意味解釈まで変わります。 >>35
[補足]
前半の通常の関数の場合、コンパイラの内部で隠れてcastされるという訳ではなく、
必要あらばちゃんとcastに必要な「変換関数」が呼び出されることまで決まって
おり、マシン語レベルで変換関数を呼び出だすcall文が生成され、その中で
変換に必要なマシン語の列が実行されます。
ところが、後半の初期化子の場合、その変換関数が呼び出されない可能性が高い
です。なぜなら、変換ではなく、最初からのコンストとラクタの仮引数の
型に合わせて意味解釈されて、いきなりその型としてコンパイルされるためです。 >>36
[補足2]
気に食わないのではなく、不規則変化というか、C++の一般法則とは異なる
法則が流れているようで、難しいな、と思ったまでです。 これvector<Entry>に
std::array<Entry,3>とか
std::tuple<std::pair<const char*, int>, std::pair<const char*, int>, std::pair<const char*, int>>
とか受け取るコンストラクタが追加されてたらまた話変わったりするよね
一応全部合法的に受け取れるはずだから、
コンパイラはどう解決するべきかってのを >>28 は聞きたいんだと思う なんか書き込んでからどっちもコンパイル通らないような気がしてきた
忘れてくれ 初期化子をコンストラクタのオーバーロード候補(静的に決まる)にそれぞれ適合させてみて、どれもダメならエラー、複数当てはまるなら優先度に従って1個に絞れたらそれを選択、曖昧ならエラー
初期化子や優先度の複雑怪奇なルール詳細の事ならともかく、この大枠の話の何がそんなに原則外れで難しいと思ってるのか正直さっぱりわからない >>37
[補足4]
fという名前だが仮引数の型が異なる持つ関数f()が複数ある場合は、
f(a);
と書いた場合、aの部分が完全に意味解釈されて、aの型が完全に決まってから、
どのf()が呼び出されるかを選択。
選択されたf()の仮引数の型Tと実引数aの型を比較して、異なっていれば、
aの型をTに変換する変換関数を呼び出し、変換後の値を関数f()の引数として
関数f()を呼び出す。
ところが、初期化子の場合、
T v = b;
と書くと、bの型を軽く調査するが、完全には b が意味解釈される前にどの T のコンストラクタ
を呼び出すべきかの調査が始まる。その時点では、bの型は完全には決まってない。 >>41
>初期化子をコンストラクタのオーバーロード候補(静的に決まる)にそれぞれ適合させてみて、どれもダメならエラー、複数当てはまるなら優先度に従って1個に絞れたらそれを選択、曖昧ならエラー
Tのどのコンストラクタを使うかが決まるまでは、初期化子の中身の型が決まりません。
なので、総当り的にチェックすることが不可能だということになります。
(原因と結果が逆なので)。
なお、Tのどのコンストラクタを使うかを決める際に、初期化子のある程度の様子は
必要になりますのでややこしくなっています。 >>36
関数だって定数(もしくは定数になる式)渡したら変換関数なんか呼ばずに変換後の値を渡すようにコンパイルするだろ >>43
型が決まらないって何のこっちゃ
君の例だと"David Hyme"はconst char*だし123456はintだし、
{"David Hyme",123456}はEntry(に集成体初期化で暗黙変換可能)で、他の要素も全部そうだから初期化子全体はinitializer_list<Entry>(に暗黙変換可能)なのでvector(initializer_list<Entry>)が適合可能、って全部静的に決まる話だぞ(正確にはもっとややこしいけど)
どこに動的型が出てくると思った? 自分の認識と実際の動作の間に食い違いがあることを質問したのに
その認識の間違いを指摘されても認めたくない人って厄介だね。 自分の認識の通りのコンパイラを作るってんならご自由にだが
そうでない以上認識を改める他なかろう >>45
動的な型のことは一切言及していません。
私のIQは170以上あるので、普通のプログラマには質問の意味が理解できてない可能性があります。 2ch/5chでレベルが高い質問をすると、バッシングを受ける傾向が有ります。 頭が良い人なら、馬鹿にも分かる説明も難なくこなすんだがなぁ
自称してるだけの馬鹿なら意味不明な話を相手の理解力のせいにするんだよなぁ >>45
例えば、class定義の中身Xが同じでも、class A {X} と class B {X} では別の型です。
その意味で、型が決まってないのです。
繰り返しますが、あなたはC言語の基礎が理解出来てないか、または、IQが
この質問に対して足りてない可能性があります。 >>52
逆も有ります。
ちなみに、私は実世界で天才だと言われたことが何度も有ります。 >>53
[補足]
{"aaa",1234}は、>>28のEntryとよく似た方では有りますが、コンパイラ内部では
Entryとは認識されません。仮に、
struct EntryB { const char *name, int number; };
とすれば、{"aaa",1234}は、中身の型としてはEntryBと全く同じと言えますが、
EntryBではないのです。
これが理解できないならば、C言語の基礎が理解出来てないので、質問の
意味が理解できないでしょう。 なお、数学的な言葉に慣れてない人は私の質問が哲学的な抽象論の様に聞こえて
頭が悪い人が変なことをいっているように聞こえたかも知れません。 >>53
>例えば、class定義の中身Xが同じでも、class A {X} と class B {X} では別の型です。
nominal typing な世界ではたしかにAとBは別の型だが無名の{X}はAとBどちらにも一致する。 あー君が何を勘違いしてるのか分かってきた
「初期化子`{"aaa",1234}`の型」というものがあると勘違いしてるんだな
こいつは「const char*とintの要素が並んだ波括弧初期化子」であってこれ全体が型を持ってるわけじゃない
あくまで「Entryを初期化(暗黙変換)出来る初期化子」「EntryBを初期化出来る初期化子」でしかなくて、これ自体をEntryとかEntryBとかそのものだと思いこんでるのが君の根本的な間違いだ
(関数呼び出しfoo(1,2);の(1,2)だけ取り出してこの型は何だ?と聞いてるのと同じようなものでナンセンス)
初期化子の仕事はあくまで初期化なんだから、同じ文字列の初期化子でもその初期化対象の型(が許している初期化方法)によって意味は変わる
Entryのようにstringとintを持った構造体なら集成体初期化になるし、
(const char*, int)の引数を取るコンストラクタ(非explicit)の呼び出しにもなるし、
initializer_list<Foo>(Fooはconst char* とintの両方から暗黙変換できる型)にもなれる
なれるというか、初期化対象型のコンストラクタオーバーロードに対して一番適合するものを探し出す(無理ならエラーにする)のがコンパイラの仕事で、当然全部静的に決まるようになってる
こういう風に同じ波括弧にいろんな解釈方法を持たせることで初期化を柔軟に書けるようになってるわけだ(C++11で導入されたuniform initialization)
キチガイみたいだから優しく教えるのはこれで最後にする
すまんかったね >>59
型を持ってるわけじゃないのは当然なのに、あなたが「動的型」というこっちが
言ってないことを勝手に妄想しだしたので、基礎から解説したまでです。
こっちの方が圧倒的に頭がいいので、食い違うのです。 馬鹿は自分が馬鹿だと気付かないんです。
質問の意味すら分かってないのに質問に答えようとしてくる。 >>59
このような場合にC++では型が静的に決まるのは当たり前。
あなたこそ、動的言語を前提にしているように思える。
そういうことではなくて、コンパイラが内部でどのような順序で「静的に」翻訳作業を
行なっているかを質問している。
コンパイラ内部では型を持って無くても、構文ツリーや色々な形でデータを
持っているが、仕様では、その順序までも決まってないとコンパイラで非互換性が
出てきてしまうし、何より、C++では演算子のオーバーロードなども出来る訳
だから、コンパイラの内部的な解釈の順序まで厳密に仕様化されてなければ、
一般プログラマも混乱が生じる。
その事を聞いている。 >>62
[補足]
JSなどの動的で初心者ならば、「大体」で理解していればそれで問題無い事が
多いだろうが、C++では、テンプレートもあればoperator+()演算子や型変換
演算子などをオーバーロードできるから、「大体」では駄目で、非常に細かな
コンパイルの順序や解釈の流れまでが言語の仕様書に厳密に書いてなければ
正しいアプリケーションコードを書くことが出来ないことがある。
「直感的に簡単に理解できるのに、何この馬鹿は聞いているんだ?」
などと思っているとすれば、大間違いだ。 質問はしたのだから、回答を待っていればいいだろうに
何でまた独り言を延々と書いてるのか、不思議だ
書くなら自分の日記帳に書けばいいのでは >>63
[補足]
>>28で、phone_bookの初期化子について、「直感的に」理解できたら
それで十分、などと考えている人は、馬鹿なので質問には答えないで下さい。
C++コンパイラは、そのように大体で動作しているのではなく、パターン
に当てはめて順序を追ってコンパイルを進めていきますが、その順序や
解釈の仕方がC++03の時代とはかなり違っているように思えたから
質問したのです。
例えば、>>28は単なる例であって、これの応用として非常に複雑なコードを
書いた場合でも、コンパイラはなんたかの単純な法則に従って厳密に翻訳していきます。
その正確な規則が分からないから聞いているのです。 >>64
馬鹿な人が茶々入れしてきたので、排除する努力をしています。 >>59
>Entryのようにstringとintを持った構造体なら集成体初期化になるし、
今回の例では、vector<Entry>型の初期化ですので、そんな単純ではありません。
vector<T,A>テンプレートのコンストラクタが呼び出されるはずです。
しかも、コンストラクタの種類が沢山ありますから、それを選ばなくてはなりません。
Entry a = {"xxx",1234};
ならば集成体初期化ですから、コンストラクタを選ぶ工程は無いはずですから、
比較的単純です。
ところが、今回の場合は、コンストラクタの選択から始まります。
しかし、初期化子自体の型が中途半端な状態でコンストラクタを選ぶ必要が
ありそうなので質問しているのです。
C++03で、x+y書いた場合、xとyの型が決まった後で、operator+(U,T)演算子を探します。
ところが今回の場合、初期化子の部分の型が中途半端な状態なので、コンストラクタを探す
ための手がかりが中途半端にしかないのです。 >>67
[補足]
CPerson person{"Suzuki", 25};
と書いた場合、CPersonのコンストラクタはすぐ探せます。
ところが、>>28 のように
vector<Entry> phone_book = {
{"David Hyme",123456},
{"Karl Popper",234567},
{"Bertrand Arthur William Russell",2345678}
};
の場合、テンプレート vector<T,A> の中のコンストラクタを選ぼうとしても、
初期化子の{"David Hyme",123456}には、ある意味では「型が存在してない」ので
通常のように探すことは出来ないのです。 >>65
正確な規則が知りたいのに規格に当たることすら思いつかないのか自称天才のボンクラ様ってのは
9.4 Initializers [dcl.init](C++20公開ドラフトN4861、正規の規格がいいなら自分で買え)を見ればいいよ
誰でも読めば分かるように書いてある規格を天才様が理解できないなんてありえないから以降質問禁止な >>68
[補足]
vectorは配列と似ていますが、コンパイラの内部的にはかなり違う扱いになっていて、
Entry a[3] = {
{"David Hyme",123456},
{"Karl Popper",234567},
{"Bertrand Arthur William Russell",2345678}
};
と書いたならば、コンパイルの翻訳過程は全く異なってきます。
この場合はとても単純で、
T a[N] = {XXX};
の形式は、配列初期化として特別処理されています。
なので、コンストラクタを探す工程、というものが必要ありません。
そして、{"David Hyme",123456} の型を知る必要も無く、単純に、
Entryのメンバに代入していくような処理となります。
この場合の処理は、まず最初に配列型として処理が入り、次にEntryの構造体型
としての処理が入ります。
これが理解できない人は質問には答えないで下さい。混乱の元になります。 >>69
そんな言い方されれば質問サイトの意味が無いわけです。 >>68
あまりにも馬鹿すぎて哀れだからもう1回だけ助け舟出してやる
いいか?vector<Entry>がどんなコンストラクタ持ってるか(どうオーバーロードされてるか)は決まってんだよ
vectorテンプレートを実体化した時点で静的に全部決まってんだよ
馬鹿なお前だって<vector>ヘッダを隅々まで読めば列挙くらい出来るのは分かるだろ
vector<Entry>のコンストラクタは例えばvector<Entry>()とかvector<Entry>(size_type)とかvector<Entry>(vector<Entry>&&)とかvector<Entry>(initilaizer_list<Entry>)とか色々あるわけだな(全部は挙げんぞ)
コンパイラ様はまずそれを列挙するわけだ。そして
・vector<Entry>()かな?→空じゃないからダメ
・vector<Entry>(size_type)かな?→{...}はsize_typeに変換できるかな?→ダメ
・vector<Entry>(vector<Entry>&&)かな?→{...}はvector<Entry>&&に変換できるかな?→ダメ
・vector<Entry>(initilaizer_list<Entry>)かな?→{...}はinitilaizer_list<Entry>に変換できるかな?→OK!
・...
ってひたすら一つずつ試すわけだ。で、vector<Entry>(initilaizer_list<Entry>)しか当てはまるものがないので、じゃあこれだとオーバーロードを解決するわけだ
コンパイラのやってることなんて基本的にこれだけだ、実に単純な話だ
こんな単純なこともわからずグチグチグチグチとお前は本当に無能だな >>72
その探し方は、普通の関数のオーバーロード解決とは異なっていますね。
しかも、あなたの言っているほど単純じゃない。
実際は、優先順位があり、先に優先順位の低いものが見つかって、後から
優先順位が高いものが見つかっても、後の方が優先される。
あなたが馬鹿なのは、単純に考えすぎていることだ。 >>71
なんで答えが書かれた文書が誰でも読めるように公開されてるのに、わざわざ自分より劣った人間に答えを求めるの?
お前天才なんだろ?ここの誰よりも賢いんだろ?
消えな >>74
すまんがお前が消えてほしい
相手するからつけあがる >>73
[補足]
なお、関数のオーバーロード解決でも、「変換できるかどうか」とかそんな単純な
ものじゃないです。
例えば、T a{x} のように{}が書いてあれば、中味が1個しか書いてなくても、
initializer_list が優先される、などと決まってます。 >>73
だから正確なのが知りたいなら規格読めやボケカス
お前のゴミ虫みたいな脳みそに合わせてわざわざ単純化してやったのに何だその物言いは無礼者の恥知らずが >>74
俺よりC++を知っている人だってこの世にいるから質問してる。
それでは質問サイトの意味がない。
調べればわかることでも知ってる人に聞いたほうが早い。 >>76
T a{x}ってそれ関数じゃなくて変数定義ですよ
そんな区別もつかないレベルじゃ規格書なんて早かったかなごめんね
でもそれも規格書に書いてあるから読んで勉強しろ >>77
あなたみたいなのが日本を衰退させている。
自分が頭がいいと思い込んでいるがかなり間違ってるし、レベルが低い。
そして、あなたの周りにはレベルの低い人しか回りに居ないから勘違いが
直らない。 >>79
アホですか。
コンストラクタを探す話をしている。 >>78
ここで俺や他の人が説明してあげてる内容すら理解できないなら、規格書を泣きながら読むか死んだほうが早いと思うよ 日本は分断化が激しい社会だ。
カシコが一部に集まり、アホがあほ同士集まっている。
だから自覚できない。
そういう社会にしてしまっていることが問題。 >>81
1行目のせいで関数のオーバーロード解決の話をしてるもんだと思ったよ
どうやらC++以前に日本語すら不自由なようだね >>82
お前は理解できてないのに質問に答えようとしている。
いつもは質問のレベルが低いから答えられているんだろうが、今回は
お前の能力を超えている。
そしていつもの調子で質問者をレベルが低いと思い込んでいるから
馬鹿にした態度をとる。 >>82
「してあげている」
って、おまえの思ってる直感的理解と、俺の求めている理解とは次元が違う。
お前は、いっぱんぴーぽーとしてC++を使えてもそれ以上はできないだろう。 もう終わりにするけど、俺の説明が間違ってるって言うならそれは規格と主要コンパイラの実装が間違ってるってことだから
ISOとベンダーに報告しときなよ
>>75
ごめんなさいみなさん久しぶりに面白いおもちゃだったのでつい std::array<T, N>って「N個の値xで埋める」コンストラクタありませんよね?
後でstd::fillするのが普通のやり方かもしれませんが、実際はstd::arrayのインスタンスができた時点でN個の何らかの初期値が入るんですよね?
この仕様に困ってます。
例えば、boost::multi_arrayは構築時にメモリの並び方 (Cライク or fortranライク) が決まって、後で変更する方法は提供されてないんですが、 std::array<boost::multiarray, N> を作ってしまうとメモリの並び方が勝手に決まってしまいます。
std::array の各要素のコンストラクタをこちらで呼ぶ方法があったら教えてください。
初期化リストで構築するやり方はNが大きいときは現実的でないので考えておりません。 >>90
残念ながらarrayで初期化時にやるのは無理
arrayは組み込み配列と同じ初期化方法(集成体初期化)しか出来ないように意図的に設計されてて特別なコンストラクタを持たない
だからarray::fill()が用意されてるので普通はそれを使う
どうしてもその場で要素のコンストラクタを直接呼びたいなら一回構築してから要素ごとにデストラクタ→placement newを呼ぶしかない
最初のデフォルト構築も許せないならarray(と組み込み配列)を使うのは諦めよう >>91
いくらアインシュタインが相対性理論を説明しても、一般人には理解できない。
どんなに天才でも、説明できない事柄がある。 天才ほど説明が下手だね
天賦の才に頼らず這い上がった苦労人タイプの
説明のほうが一般人には分かりやすい わかった気になるだけってやつね
完全に理解する必要のない一般人ならそれもあり 確かに右辺値参照あたりの仕組みはコピー減らそうという意図が感じられる割に徹底しようとするとstd::arrayとかのctorで足元すくわれがち arrayは組み込み配列の糞さ緩和が目的なので糞が多少まろび出るのは仕方ないんよね >>92
collectionで初期化も無理なんだ?
せめてvectorで初期化できるなら良かったのにね 1つでもコンストラクタを独自定義したら集成体になれないので仕方ない >>90
要素のデフォルトコンストラクタは呼ばれるので要素のほうに適当なラッパーを被せるという方法はとれなくはない。
こういうラッパーならスタンダードレイアウトの要件は満たすのでバイト列レベルでも互換性は維持されるはず。
#include <array>
#include <iostream>
struct foo {
// このコンストラクタを呼んで欲しい
foo(int x){
std::cout << x << std::endl;
}
};
template <class T, auto N>
struct initializing_wrapper : public T {
initializing_wrapper(void) : T(N) {}
};
int main() {
std::array<initializing_wrapper<foo, 1> , 3> foo;
} vscodeでeigen使ったコード書いてるんだけど、デバッグ時にeigenの変数見る方法ある?
visualstudioならあるっぽいんだけど、vscode上でしょりしたいんだよね ちょ、何これ? 聞いてないんだけど。。。
C:/msys64/mingw64/include/c++/12.2.0/bits/stl_pair.h:326:13: note: declared here
326 | pair& operator=(const pair&) = delete;
C:/msys64/mingw64/include/c++/12.2.0/bits/stl_pair.h:715:5: note: declared here
715 | swap(pair<_T1, _T2>&, pair<_T1, _T2>&) = delete; >>103
eigen一回も使ったことないしググってもないけど、行列の先頭要素のメモリにアクセスする方法が提供されてないわけないので、それを使う
普通はdata()とかget()なるメンバ関数がある 壮大なSFINAEってわけか・・・
元コードは晒せないんであとは自分で探すしかないな
ヒントありがと、餃子さん どうせ使えないなら使おうとしたときに static_assert で問題点を出すようにしたらいいのにと思ったがよく考えるとそれは駄目なんだな。
適用できるものがないということを SFINAE のトリックに使うことがあるかもしれない。
(static_assert が展開されると他の候補があっても問答無用で終わりになってしまう。) >>94-95
天才とパンピーで理解レベルのバックグラウンド知識に差があるからだろ
その差を埋める説明を一瞬で出来る人はそれなりの才能があるとは思うが
天才同士ならそんな説明いちいちしなくても判り合えるんだ 自分が天才だ!とわざわざ自称しなくても、天才らしい雰囲気をかもし出せるレスはないものでしょうかね…
自称天才はもういいし プログラミング言語 C++ [第四版], 日本語訳 の p.689 に、
template<typename T>
class Xref {
・・・
};
template<typename TT, typename A>
unique_ptr<TT> make_unique(int i, A&& a)
{
return unique_ptr<TT>{new TT{i,forward<A>(a)}};
}
auto p1 = make_unique<Xref<String>>(7,"Here");
「ここで、"Here"は右辺値なので、右辺値を引数にしてforward(string&&)
が呼び出される。」
とありますが、実引数の文字列リテラル "Here" が、make_unique()の
仮引数 A&& に渡そうとしたら、A = string と「演繹」されているようですが、
const char* 型が string に至るまでの仕組みか分かりません。
どなたが分かる人居ませんか?
実際の STL の sting は basic_string<U> テンプレートの U=charの
場合だと思われますが、意味を概念的に言えば、
class string {
public
// 変換コンストラクタ :
string(const char *) {・・・}
};
という「変換コンストラクタ」があるでしょうから、それが使われている
ことは推定は出来ます。
しかし、上記のテンプレートで T を演繹する際に、このような変換コンストラクタ
が呼び出されるメカニズムが分かりません(仕様書のどこに書いてあるのかが
分からない。)。 >>117
もっと詳しく書くと、直前から次のように書かれています:
# Xref<String>はXref<string>の写し間違いでした。
string x {"There and back again"};
template <typename T>
T&& std::forward(typename remove_reference<T>::type& t) noexcept;
template <typename T>
T&& std::forward(typename remove_reference<T>::type&& t) noexcept;
ここで望まれるのは、不純なコピーを一切作ることなく、
make_unique<T>(arg)がargからTを構築することである。
その実現には左辺値と右辺値の区別を管理することが重要だ。
次の例を考えてみよう:
template<typename TT, typename A>
unique_ptr<TT> make_unique(int i, A&& a) // make_sharedのちょっとした変種
{
return unique_ptr<TT>{new TT{i,forward<A>(a)}};
}
auto p1 = make_unique<Xref<string>>(7,"Here");
ここで、"Here"は右辺値なので、右辺値を引数にしてforward(string&&)
が呼び出される。
そして、"Here"を格納しているstringのムーブを行なうために、
Xref(int,string&&)が呼び出されることになる。
# 個人の感想: これは、A=stringと考えられます。
もっと興味深い(しかも分かりにくい)のが、次のものだ:
auto p2 = make_unique<Xref<string>>(9,x);
ここで、xが左辺値なので、左辺値を引数にforward(string&)が呼び出される。
forward()のTは、string& と導出される。そのため、返却値は string & &&となる。
もちろんそれは string & を意味する(§7.7.3)。その結果、左辺のxに対して、
Xref(int,string&)が呼び出されて、xがコピーされる。
# 個人の感想: これは、A=string&と考えられます。 >>118
[参考]
p.724,
「文字列リテラルは、テンプレート引数には『渡せない』」
ただし、これがどう関係しているのかは不明です。
A&& a の部分に文字列リテラル"Here"を渡してはいますが。 ある型が来たらそれに応じた変換をするのが、何か問題なんでしょうか make_uniqueの実体化の所でTT=Xref<String>、T=Stringって明示的に指定してるじゃん
「演繹」なんかするまでもないから規格に書いてるはずもない
天才のくせにそんな事も分からないの? >>119
[ヒント]
前頁p.688の下段:
「左辺値と右辺値は、テンプレート引数の導出では区別される。
X型の左辺値はX&として導出されて、右辺値はXとして導出される。
これは、非テンプレート引数の右辺値参照への値のバインド
(§12.2.1)とは異なる。
しかし、引数転送(§35.5.1)においては、極めて有用だ。
Xrefを空き領域上に置いて、そのポインタをunique_ptrとして
返すファクトリ関数を記述する場合を考えてみよう:
」
の直後、ページが変わってページの最初に>>118の std::forward テンプレート
の定義が書いて有ります。 引用の範囲超えてるんで著作権侵害の疑いで削除依頼出しますね >>121
TTは、Xref<string>と明示的に指定されてますが、AはTTとの関係は
書いて無いはずです。
なので、それだけでは、A=stringとは分からないはずでは。 new TT{i, forward<A>(a)}
既出だが、こう書いてあってもXrefのメンバの型がどうなるか分からんわけでしょ
先日の質問と合わせて、型パズルをスラスラ解けるような資質がない
資質がないんでXrefの『関係ない』としたところを「・・・」で埋めてる >>117
どういう文脈で説明されてるのかよくわからんが
引数が文字列リテラルの "Here" なら A は const char (&)[5] に推論されるよ。 >>126
命題『A が const char (&)[5] に推論される』・・・☆
とし、背理法で考えます。
☆が正しいと仮定すると、
forward<A>(a)は、forward<const char (&)[5]>(a)となりますが、すると、
template <typename T>
T&& std::forward(typename remove_reference<T>::type& t) noexcept;
template <typename T>
T&& std::forward(typename remove_reference<T>::type&& t) noexcept;
に対して、forward<const char (&)[5]>(a)
が呼び出されることになります。
しかし、
>auto p1 = make_unique<Xref<string>>(7,"Here");
>ここで、"Here"は右辺値なので、右辺値を引数にしてforward(string&&)
>が呼び出される。
とBJ stroustrup氏が書いています。
ならば、T=const char (&)[5]の時に、
typename remove_reference<T>::type
がstringにならなければなりません。つまり、
typename remove_reference<const char (&)[5]>::type
がstringになってないと矛盾する事になります。
もし、矛盾するならば、背理法により、☆は否定されることになります。
(矛盾しそうです。) >>127
これは背理法とは言わなかったわ。
スマソ >>127
> ここで、"Here"は右辺値なので、右辺値を引数にしてforward(string&&)
> が呼び出される。
文字列リテラルは左辺値。 右辺値だと書いてあるのならそれが間違っている。
配列がポインタに (暗黙的でも明示的でも) キャストされる文脈では
そのポインタは xvalue (おおよそ右辺値のような扱いになる分類) になるが、
今回は変換が入らずに参照で受けているのでそうはならない。
/// この場合は rvalue 扱い
#include <cstdio>
void foo(const char *&x) { std::printf("lvalue"); }
void foo(const char *&&x) { std::printf("rvalue"); }
int main(void) { foo("abc"); }
/// この場合は lvalue 扱い
#include <cstdio>
template <class T> void foo(const T &x) { std::printf("lvalue"); }
template <class T> void foo(const T &&x) { std::printf("rvalue"); }
int main(void) { foo("abc"); } 文字列リテラルは実際は配列
⇒アドレスで区別できるメモリ上のオブジェクト
⇒つまりlvalue 文字列リテラルはメモリ上に永続的に保持されるんだから勝手に持ってっちゃダメでしょ 文字列リテラルは配列型のlvalue
文字列リテラルが左辺値変形されて生じたポインタはrvalue 配列 (文字列を含む) と関数は値として扱えない、勝手にポインタに型変換するという
C から引き継いだ変則的なルールに辻褄を合わせているので全体的に変則的で
分かりにくいんだよ……。 >>131
>auto p1 = make_unique<Xref<string>>(7,"Here");
>ここで、"Here"は右辺値なので、右辺値を引数にしてforward(string&&)
>が呼び出される。
と書かれています。
なので、"Here"がなんらかのメカニズムでstd::stringに変換されていると
解釈しました。
実験すれば白黒はっきりさせることが出来るかも知れません。 マジで間違った方向に引きずり回してんのか
やっぱりすげーな
こいつは上級者だ >>138
C++の父であるところのBJ Stroustrup氏が直々に書いていることなのですが。 禿本手元にないから確認はできないけど、「"Here"が右辺値」なんて基本的な間違い書くとは思えないんだけど
侵害くんの読み間違いか書き間違いか、本当に書いてあるなら翻訳ミスじゃないの >>139
"Here"の配列→(配列とポインタの糞ルール)→const char*→(stringの変換コンストラクタ)→string
と変換された結果のstring一時オブジェクトが右辺値だってクドクド書いてない?ちゃんと読んだ? 原書(英語版)はこうなってます:
23.5.2.1. Reference Deduction
...
template<typename T>
class Xref {
public:
Xref(int i, T* p) // store a pointer: Xref is the owner
:index{i}, elem{p}, owner{true}
{}
Xref(int i, T& r) // store a pointer to r, owned by someone else
:index{i}, elem{&r}, owner{false}
{}
Xref(int i, T&& r) // move r into Xref, Xref is the owner
:index{i}, elem{new T{move(r)}}, owner{true}
{}
~Xref()
{
if(owned) delete elem;
}
//...
private:
int index;
T* elem;
bool owned;
};
... >>142
template<typename T>
T&& std::forward(typename remove_reference<T>::type& t) noexcept; //§35.5.1
template<typename T>
T&& std::forward(typename remove_reference<T>::type&& t) noexcept;
template<typename TT, typename A>
unique_ptr<TT> make_unique(int i, A&& a) // simple variant of make_shared (§34.3.2)
{
return unique_ptr<TT>{new TT{i,forward<A>(a)}};
}
We want make_unique<T>(arg) to construct a T from an arg without making any spurious copies. To do that, it is essential that the lvalue/rvalue distinction is maintained. Consider: auto p1 = make_unique<Xref<string>>(7,"Here");
"Here" is an rvalue, so forward(string&&) is called, passing along an rvalue, so that Xref(int,string&&) is called to move from the string holding "Here". The more interesting (subtle) case is: auto p2 = make_unique<Xref<string>>(9,x); Here, x is an lvalue, so forward(string&) is called, passing along an lvalue: forward()’s T is deduced to string& so that the return value becomes string& &&, which means string& (§7.7.3). Thus, Xref(int,string&) is called for the lvalue x, so that x is copied.
Stroustrup, Bjarne. The C++ Programming Language (p.689). Pearson Education. Kindle 版. C++ど素人なんですが、この画像のようなファイル群がある時に、Visual Studioでexe化するにはどうしたら良いですか?
まず、ファイルはsln形式などになってないですが、そういったものはつくる必要はなく、ExpressionApp.cppだけ開いてビルドボタンを押したりすれば良い感じなのでしょうか? >>140
"Here" is an rvalue, so forward(string&&) is called, passing along an rvalue, so that Xref(int,string&&) is called to move from the string holding "Here".
>>141
テンプレート関数なので、Aという方引数が決定されるメカニズムが重要となります。
Aがstringに決定されたならば、文字列リテラルからstringへの変換法則はおなじみの
ものとなります。
それよりも、まず、どうしてAがstringに決定されたのかの「仕組み」が分かりません。 >>143
142と143の間に、次の記述が挟まっています。
So:
string x {"There and back again"};
Xref<string> r1 {7,"Here"}; // r1 owns a copy of string{"Here"}
Xref<string> r2 {9,x}; // r2 just refers to x
Xref<string> r3 {3,new string{"There"}}; // r3 owns the string{"There"}
Here, r1 picks Xref(int,string&&) because x is an rvalue.
Similarly, r2 picks Xref(int,string&) because x is an lvalue.
Lvalues and rvalues are distinguished by template argument deduction:
an lvalue of type X is deduced as an X& and an rvalue as X.
This differs from the binding of values to non-template argument rvalue references (§12.2.1)
but is especially useful for argument forwarding (§35.5.1).
Consider writing a factory function that make Xrefs on the free store and returns
unique_ptrs to them: >>137
文字列リテラルが lvalue なのはややこしい解釈の余地はなく直接的に明記されている。
https://timsong-cpp.github.io/cppwp/n3337/expr.prim.general#1
少なくとも
> "Here"は右辺値なので
というのは確実に誤った記述だよ。
最初の段階で誤っているのだからそこから後の理屈の立て方に筋が通るはずがない。
>>148
A は string に決定されない。
そういう仕組みは無いのでそれを前提として考えるな。 >>152
>A は string に決定されない。
>そういう仕組みは無いのでそれを前提として考えるな。
なるほど。しかし、だとすれば、
「Consider: auto p1 = make_unique<Xref<string>>(7,"Here");
"Here" is an rvalue, so forward(string&&) is called, passing along an rvalue,
so that Xref(int,string&&) is called to move from the string holding "Here".」
の部分はどう説明できますか? >>153
今思ったんですが、もしかしたら、
>Consider: auto p1 = make_unique<Xref<string>>(7,"Here");
の部分が、
Consider: auto p1 = make_unique<Xref<string>>(7,string{"Here"});
の書き間違いだったのかもしれませんね。
なお、直接関係有りませんが、>>150の
>Xref<string> r1 {7,"Here"}; // r1 owns a copy of string{"Here"}
>Here, r1 picks Xref(int,string&&) because x is an rvalue.
は、確認しましたが、kindle版は確かに正確にこう書かれていますが、
このr1の定義部分に「x」は存在しておらず、代わりに"Here"が存在していますので
そこも書き間違いかも知れません。 もしくわ、
>auto p1 = make_unique<Xref<string>>(7,"Here");
は、
auto p1 = make_unique<Xref<string>,string>(7,"Here");
と書きたかったのでしょうか。つまり、もし、
auto p1 = make_unique<Xref<string>>(7,string{"Here"});
または、
auto p1 = make_unique<Xref<string>,string>(7,"Here");
と書いてあったならば、辻褄が合いそうです。 文字を反転させる関数を作っているのですがうまく行きません
voidの部分がおかしいと思うんですが正直手詰まりです
誰か解決策はありますでしょうか
実行するとrevarce関数が飛ばされて終了してしまいます
void revarse(char* p, char* r);
int main(void)
{
char str1[64];
char str2[64] = {};
printf("文字列を入力\n>>");
scanf("%s", str1);
revarse(str1, str2);
printf("%s", str2);
rewind(stdin);
getchar();
return 0;
}
//反転させる関数
void revarse(char* p, char* r)
{
int len = strlen(p);
for (int i = 0; i <= len / 2; i++)
{
*(r + i) = *(p + (len - i));
}
} >>156
文字列pが "12345" だとして考えてみ?
len=5 だろ?
*(p + (len - i));
これって i=0 の時 *(p + (5 - 0)) => *(p + 5) ってことになる
ゼロベースだからインデックス5にはNULL文字'\0'が入っている
それを*r にコピーしている
つまりコピーされるのは常に長さ0の文字列
そりゃ出力したってなにも表示されないさ
あとlen / 2はおかしいだろ
練習するならマルチバイトはまず置いておいてシングルバイト文字のみ扱え >>158
ありがとうございます!
助言道理に直したら無事に反転させることができました!
本当にありがとうございます!
精進します! int と N 要素の vector<double> から N+1 要素の tuple<int, double, double,...> を作る方法ってありますか >>142
よく見るとデータメンバの名前が owned なのに初期化のほうでは owner になってるな。
実際にコンパイルしてみようとして気づいたわ。 >>144
>>147 が正解だが
Readme.txt も読んだか? >>148
clang に抽象構文木を見る機能があるのを思い出した。
それを通したらこんな感じ。
https://wandbox.org/permlink/NNaci7k0QcpFXc9G
表示の正確な読み取り方はワイも知らんのやが lvalue "Here" と出てるのはわかるし、
関数に渡したときに const char (&)[5] として受け取られているのはわかるやろ。 >>161
vectorの取りうるサイズがある程度決まってるのなら
予めdoubleの数が異なるtupleを用意しておくという手はある
#include <iostream>
#include <any>
#include <vector>
#include <tuple>
using namespace std;
using Vector = vector <double>;
using Int_Double_1 = tuple <int, double>;
using Int_Double_2 = tuple <int, double, double>;
any make_tuple_from_int_vector (int p0, const Vector &p1)
{
if (p1.size () == 1)
return make_tuple (p0, p1 [0]);
else if (p1.size () == 2)
return make_tuple (p0, p1 [0], p1 [1]);
else
return any ();
}
int main ()
{
Vector v1 (1, 10);
Vector v2 (2, 100);
auto v3 (any_cast <Int_Double_1> (make_tuple_from_int_vector (1000, v1)));
auto v4 (any_cast <Int_Double_2> (make_tuple_from_int_vector (10000, v2)));
return 0;
} true &&false計算するのと1&&0計算するのはどっちが早いとかある? はちみつもたまには役に立つな。
褒めてつかわす。
下がって良いぞ。 >>172
オペランドがリテラルならコンパイル時に畳み込まれるので同じ。
そうではなく型による差について問うているのなら
少なくとも現代的な処理系・実行環境だとまず差は出ないよ。
うまいこと最適化されてそんな差はどうでもよくなる。
言語仕様通りの素朴な解釈だと両オペランドを bool に型変換するという工程が入るので
int の && のほうが余計に処理をすることにはなるが……。
ちなみに C と C++ では規則が違うので詳細を調べるなら混同しないように注意。
(文言は違うけど結果的な挙動はほぼ差はないんだけど。) >>172
どちらも、最適化されれば false(偽) になって同じコードになる。 >>176
[補足]
最適化には高レベルから低レベルまでさまざまな層で行なわれる。
高レベルで複雑な多くのマシン語が生成されても、後段の低レベルで集成されて短い
コードになる。
&& や || は、シーケンスポイントがあり A && B は A が偽ならば B を評価しないし、
A || B は、A が真なら B を評価しないので、マシン語レベルで条件 jump 命令が
生成されることが有るが、&& や || は、「高レベル」でも最適化する方法が
知られているので、このような場合、条件 jump 命令が生成されない。
また、仮に高レベルでは条件 jump 命令が生成されてしまった場合でも、
低レベルで最適化する際に、必ず真になったり必ず偽になるような条件 jump は、
無条件jumpになったり、削除されたりする。
そして、直後の命令への無条件 jump は、削除される。
二段階の無条件 jump は一段階の jump に修正される。
このような最適化を何度も何度も繰り返すので、結果的に同じことをするコードは、
同じコードになることが多い。 >>177
誤:最適化には高レベルから低レベルまでさまざまな層で行なわれる。
正:最適化は高レベルから低レベルまでさまざまな層で行なわれる。
誤:高レベルで複雑な多くのマシン語が生成されても、後段の低レベルで集成されて短い
正:高レベルで複雑な多くのマシン語が生成されても、後段の低レベルで修正されて短い windowsでstd::create_symlinkを使おうとすると
特権がいるって言われるけど、何でそんな決まりになってんの?
mklinkコマンドも特権モードじゃないとシンボリックリンク作れないし
それのどこがそんなに危険な操作なのか理解に苦しむ 権限のないディレクトリにシンボリックリンクを作ろうとしてるのでは? C:じゃないHDDだし俺専用PCだし
所有権でややこしいことにはなりっこない ディレクトリの権限関係なくWindows のシンボリックリンクの作成自体に管理者権限が必要、理由は知らん
ディレクトリにリンク張るならジャンクション(こっちは管理者権限不要)使えってことかも
ジャンクションの作成はコマンドからならmklink /jで行けるけどコードからやるのはちょっと面倒みたい
https://stackoverflow.com/questions/29291059/issue-creating-windows-ntfs-directory-junction-in-c-c 一般人に使わせるとショートカットと混同して危険だからそうしてるってどっかで見た
何が危険なのかは分からなかった >ユーザー権利を持つユーザーは、誤って、または悪意を持ってシステムをシンボリック リンク攻撃に公開する可能性があります。
>シンボリック リンク攻撃は、ファイルのアクセス許可の変更、データの破損、データの破棄、または DoS 攻撃として使用できます。
というのが、Microsoft の公式見解 >>185
読んでもサッパリ分からん
なんすか? その「シンボリックリンク攻撃」って?
それUNIXでは生じないの? >>185
これソースある?
シンボリック経由でファイルやフォルダーの権限って変わるんだっけ? >>188
リンク先には攻撃方法は書いてないな
シンボリックリンク攻撃 でググるとこれが出てきた
特にWindows特有というわけじゃなさそう、て言うかWindowsは/tmpみたいな誰もが共通的に使うディレクトリはないからより攻撃は難しそうだが
https://www.ipa.go.jp/security/awareness/vendor/programmingv2/contents/c802.html 他の人の書いたコードを読み解いています。
下の例では、キーが押されたら何かを切り替えてるのはわかるのですが、ここで使われている
・0xFの意味
・(1 << 0)などの右シフト?
がどういう使われ方をしてるのかが分からないので知りたいです。
16進数で掛け算して値を使っているのでしょうか?
単純な1,2,3,4などの数値で切り替えていないのも意図がよく分からないのでずが深い意味はありそうでしょうか?
// VIEW_MESH | VIEW_IMAGE | VIEW_PLOT | VIEW_LM
int _viewMode = 0xF;
enum
{
VIEW_MESH = (1 << 0),
VIEW_IMAGE = (1 << 1),
VIEW_PLOT = (1 << 2),
VIEW_LM = (1 << 3)
};
switch (key)
{
case 'i': _viewMode ^= VIEW_IMAGE; break;
case 'l': _viewMode ^= VIEW_LM; break;
case 'm': _viewMode ^= VIEW_MESH; break;
} >>190
>・0xFの意味
16進数、10進数の15、2進数の1111
> ・(1 << 0)などの右シフト?
左シフト、1 << 0に関して言えば0ビットシフトなのでつまりシフトしない、二進数で0001、10進数で1
(1 << 1)は1ビット左にシフトなので二進数で0010、10進数で2
(1 << 2)は2ビット左にシフトなので二進数で0100、10進数で4
(1 << 3)は3ビット左にシフトなので二進数で1000、10進数で8 >>190
^= は複合代入演算子
_viewMode ^= VIEW_IMAGE は _viewMode = _viewMode ^ VIEW_IMAGE と同じ
^ は排他的論理和(ビットXOR)、二進数で 1001 ^ 1100 は 0110 になる、要はビットが同じなら偽、異なっていれば真という演算
>case 'i': _viewMode ^= VIEW_IMAGE; break;
_viewModeには1111が代入されている、VIEW_IMAGEは0010
1111 ^ 0010 は 1101 になる
その演算結果1101を_viewModeに代入する
一連のコードはビットをフラグとして扱っていて、初期値として全フラグを立たせ、keyに対して特定のフラグをへし折っている >>191
>>192
ありがとうございます
なるほど!フラグをへし折っているのですね納得です 論理演算とか知らない奴がプログラムやっているんだな・・・ 始めたばっかりなんでしょ
ビットをフラグとして使うとか最初は面食らったな ファミコンでもあるまいし、いまどき1ビットに意味をもたせなんて、通信制御くらいしか思い付かないなぁ マシン語のレベルで、演算結果を示す幾つかの1ビットデータがあって
それらにキャリーフラグ、ゼロフラグなどの名前が付いてたのが呼び方の元 >>196
経験値が低いだけだろ
APIとか使ってたら普通に使うわ >>200
そうか?普通#defineされてる名前を使うからあんま意識しないよ? >>201
defineされてようが複数のフラグをand/or で繋いだりするのは桁で管理してるからじゃん さっきのビット演算、XOR 使うってことは
key によって特定のビットをトグルで ON/OFFする処理
の一部を抜粋した様に見える >>201
複数フラグを同時に使う時は FlagA | FlagB とかやるんだが意識してないお前はどうやってるんだ?w >>192
>二進数で 1001 ^ 1100 は 0110 になる
いまさらだけどここ間違えたわ
「二進数で 1001 ^ 1100 は 0101 になる」が正しい 現代的な C++ なら std::byte とか std::bitset を使って欲しいところではある。 istringstreamとかifstreamとかistreamとか
入力系からreadした場合実際に読めたバイト数は
.gcount()で取得出来ますが
ostringstreamとかofstreamとかostreamとか
出力系にwriteした場合実際に描き込めたバイト数はどうすれば取得出来ますか?
.pcount()とかは無いようです writeに文字数与えてるだろ?成功したらその数だよ
失敗したら未定義 Nを指定して成功していたら必ずNは判りますが
未定義: 失敗したとき0かどうかは判らない
定義済(0): 0からNの間の値になる可能性は無い
の未定義にあたるということですかね
途中までならその途中までの数字が知りたいと思うのは不自然?
ありがとうございます write(2)じゃなくてfputs(3)に相当するから
書き込んだバイト数なんて概念はないのでは 書き込みエラーなんてプログラムからは何が起きてるかわかんないんだよ
最悪壊れかけのディスクにちょうどトドメ刺して何もかも吹っ飛んだのかもしれない
エラーが起きた時点でプログラム側で保証できることなんてほとんどないし、たまたま途中の何文字まで書けたかなんて大抵は無意味な情報
逆に読み込みで何文字読んだって情報は、プログラム側で管理してるメモリの話だからプログラムからも分かるし必要でもある テキストアライメント関係の 始端よせ/中央/終端よせ の類で
0~3の 2 bit値を ビットパターンマスクの途中に織り込んでくるのはどっきりする 質問なのですがenum class初心者なのですが
enum classはint以外の整数型としても定義できるそうなので
整数型への自動変換ぐらいしてくれるのかと思いきや、
enum Foo { A, B, C, D, N };
int arr[Foo::N];
arr[Foo::A] = 1;
arr[Foo::B] = 999;
みたいに配列の添え字に使うケースで
error C2677: 二項演算子 '[': 型 'Foo' を扱うグローバルな演算子が見つかりません (または変換できません) (新しい動作; ヘルプを参照)。
というコンパイルエラーになります……orz
Visual Studio 2019なのですがおれ環? レス㌧クス
なるほどキャスト必須ですか、、、
Fooへの整数の代入だけエラーになるのかと思ったら
思ってたのと違う…… スコープを限定したいときは以下のように俺は書いてるな
namespace Foo
{
enum { A, B, C, D, N };
}
int main ()
{
struct Bar
{
enum { A, B, C, D, N };
};
int arr0[Foo::N];
arr0[Foo::A] = 1;
int arr1[Bar::N];
arr1[Bar::A] = 1;
return 0;
} >>217
enum class といいつつ enum で宣言しているところをみるに、
ひょっとして enum と enum class が別物であることを知らずに混乱しているのでは?
ちなみに enum class も class というキーワードを使いはするが分類上はクラスではないのも混乱するかもな。
> enum classはint以外の整数型としても
たぶん underlying type のことを言っているんだと思うが
指定しなかったときの underlying type は int ではなく
その列挙体における全ての列挙子を格納可能な処理系定義のなんらかの整数としか決まってない。
(格納可能である限りは int より大きくなることはないという制約はついているけど。) >>223
> 指定しなかったときの underlying type は int ではなく
> その列挙体における全ての列挙子を格納可能な処理系定義のなんらかの整数としか決まってない。
> (格納可能である限りは int より大きくなることはないという制約はついているけど。)
それunscoped enumeration typeの方
enum class は無指定だと int になる
https://cpprefjp.github.io/lang/cpp11/scoped_enum.html >>223
>>217でenum Fooと書いたのはenum class Fooの誤記でしたサーセン;;;;
enum classを自動では整数型に変換してくれないのはやっぱおれ環? C++の言語仕様を決めてる人たちの考えとしては
配列とハッシュはまったく異なる概念なので分けて使うようにってことですか? 逆に聞きたいが
配列とハッシュが同じカテゴリに入ることなんてあるのか? 歴史的経緯というやつだなぁ。
C では列挙子の型が int なんだよ。 列挙型は定義ごとに独立した型になるのに列挙子は整数そのものとして扱われる。
C++ では列挙子の型は列挙型に変更しつつも型変換がゆるゆるだから結果的に C とほぼ同じ挙動になって互換性が維持された。
あまりよくはないが C との連携は C++ の強みだから仕方がない。
でもさすがに扱いにくいから新しく enum class が作られたという経緯なので最初から使い分けを意図して二種類作られたわけではない。
enum の改良として enum class が出来たので一貫性がなく全く別物として成立している。 >>228
PerlのハッシュはC++ではmapやsetっていうんだね
ただ今勉強中で頓珍漢なこと言ってしまった、すいません >>231
mapは写像、setは集合が大本の概念だからな。
Hashはハッシュ関数という写像の一種だから、正確には同じじゃない。 簡単そうに見えたけど、俺の中でなかなか理解できないのが explicit 指定。
明示的初期化、直接初期化、代入初期化(?)、暗黙の型変換の禁止、
などなど色々な概念があるし、頭の中で整理できてない。
「直接初期化」の定義が今一分かって無い。 >>235
もちろん色々な概念と相互に関係はあるんだが explicit 指定に直接的に関連するルールは
・ 引数一個で呼び出せるコンストラクタ (デフォルト引数や可変長引数の場合も含む) は変換コンストラクタ (converting constructor) としても機能する
・ ただし explicit 指定がついている場合はそうならない
ってだけだな。
変換コンストラクタがいつ起動するのかはまた別の話として……。 C++03まではそうだったけど
11から複数引数にも波括弧からの変換を認めない機能が追加されてややこしくなってる
struct Hoge{
/*explicit*/ Hoge(int,double,char*);
…
};
Hoge foo(){
return {42,3.14,”Hello”); // explicitだとダメ
}
Hoge h[] = { {1,1.0,””}, {2,2.0,””}}; //explicitだとダメ ハッシュを使って実現した連想配列をハッシュって呼ぶのは
携帯電話をケータイと呼ぶような類のこと >>238
誤用の無い範囲で用語を混同するのは理工学じゃ普通。 >>237
こういうこと?
#include <iostream>
using namespace std;
struct Hoge{
int a;
double b;
char *c;
explicit Hoge(int _a, double _b, char *_c) : a(_a), b(_b), c(_c) {}
};
Hoge foo(){
return Hoge{42, 3.14, "Hello"};
}
Hoge h[] = {Hoge{1, 1.0, ""}, Hoge{2, 2.0, ""}};
int main() {
return 0;
} そのへんの仕様を何度も読んだことは記憶にあるのに内容はなんも覚えとらん。
実際わかりにくいと思うわ。 今まで本を読んでも、「直接初期化」「コピー初期化」
の厳密定義が分からなかったけど、英語版の en.cppreference.com
をそれぞれ
「direct initialization」「copy initialization」
で検索すると「全てのパターン(?)」の一覧が出てくるみたいだ。 >>241
それはただのHogeのコピー
波括弧からの暗黙変換を禁止するのがexplicit あ、第3引数const char*じゃないとダメだったすまん >>231
ハッシュは数学的な関数で
辞書とは根本的に違うぞ >>247
しつこいって、こっちから意見を述べたのはこれが最初なんだが??
PerlではどうたらをC++スレで押しつけようとしているおまえさんこそ
しつこそうだぞ
嫌なら出てけよ、余所者 explicit……
ある型を別の型にするコンストラクタを定義したのだけど
暗黙の型変換は辞めて欲しいときに使う(使った C++スレでPerlマウント取りに来たの?
ダサすぎwww 本国で相手されないからってするに事欠いて、ちったあ恥を知れよ >>252
アスペか?
>>228 は単に勉強不足だって書いてるのに押し付けるとか頭おかしい > >>231
> ハッシュは数学的な関数で
> 辞書とは根本的に違うぞ
之大いに我が意を得たり
ハッシュ関数使わなくても連装配列実装できるもん遅いけど
ていうかハッシュが衝突したらそこから先は線形探索か何か(通常の実装では
なので連装配列をハッシュと呼ぶ風潮は嘆かわしいPerlerの端くれだけど >>257
>そこから先は線形探索か
ダブルハッシュですよ普通は
つまりまずは違うハッシュ関数を使いますね、それからやっと線形探索かな >>255
医学用語持ち出して感情に働きかけるあたり
論理思考が苦手そうな方ですね
ご自慢のPerlを自ら貶めていることにお気づき召されよう・・・ 医学用語?
ネットスラングやぞw
----
ネットスラングなので明確な定義はなく、用法は人によるところだが、おおむね下記のような人間を指すことが多い。
■コミュニケーションが苦手(コミュ障):話や文章の理解力が乏しい、円滑な意思疎通が困難、空気が読めない、相手の感情を察知できない。
■拘りが強い:些細な間違いを指摘し揚げ足を取る、自分の作ったものに手を加えられるのを嫌う(ここやwikiで言う自治厨)、理想とするパターンをもっておりそれを邪魔されるとヒステリックになる。
■短気:上記のような過ちを指摘されると反射的に逆上する。
■独善的:ロジカルシンキングが出来ず自分が悪いという思考に思い至らない。
https://dic.pixiv.net/a/%E3%82%A2%E3%82%B9%E3%83%9A >>262
> 医学用語持ち出して感情に働きかけるあたり
> 論理思考が苦手そうな方ですね ハッシュとはそもそも何かがわかってなくて頓珍漢なこと言って恥かいたやつは
こういう低レベルな煽り合いになると喜んでついて来やがる そもそもC++ではそのデータ構造のことunordered_mapって呼ぶんですよ
スレ違いやめてください 最近の人はハッシュと言えば#しか思い浮かばんだろうから
perlの連想配列とか#hoge{'fuga'}とか描いてバグ理想 perl界隈で連想配列のことハッシュとか言ってる人知らないな
何十年も前からみんな連想配列連想配列言ってたでしょ
最近はハッシュって呼ぶ人もいるのかな?
むしろRubyの方なら昔から組み込みライブラリに
その名も Hash っていうそのまんまのクラスがあるから分かるけど いちいち連想配列って言ってる人を逆に見かけたことないが。perl用語ではhashなんだし。 >>270
まだやるの?
公式がハッシュって言ってるのになに言ってるんだよ
Perl has three built-in data types: scalars, arrays of scalars, and associative arrays of scalars, known as "hashes".
https://perldoc.perl.org/perldata#NAME そうなん?(ヽ´ω`)
ちなみに手元のラクダ本1993年発行には
> P.37 この章の最後を締めくくる話題は連想配列である。
> 連想配列を自在に使いこなせるようにならなければPerlを究めたとは言えない。
> (略)連想配列を使えば(略)連想配列は(略)連想配列から(略)
> これが連想配列(略)連想配列も(略)連想配列全体を表すには(略)
とあるわ ラクダは連想配列だよな
何時からか知らんが#が主流になった
糞Javaの影響かも知れん
使い方で世代が判るんじゃね
知らんけど >>272
>associative arrays of scalars, known as "hashes"
まともな英語力あるなら
連想配列が主でハッシュが副だと読めるだろ >>274
Map的なものに対する呼び方で
その人のバックグラウンドが透けて見えて少し面白いよね
map ←C++
連想配列 ←Perl
Hash ←Ruby
Map, Hashtable ←Java
Dictionary, Hashtable ←C# >>276
そのページで associative array と書いているのはその一か所だけで、
あとは全部 hash と呼んでいるのは見りゃわかるだろ。 >>276
「ハッシュとして知られている」な
理解力無さすぎだろw hash table→associative array→map→dictionaryの順に抽象度が高い呼び方なだけで、どれが合ってるとか優れてるとかいう話じゃないね
hashは略し過ぎで誤解や混同を招くバカ丸出しの呼び方だと思うけど、それで定着しちゃってるバカ言語はしょうがないから使い続ければいいと思うよ
だからバカ言語erは帰ってくれないか >>279
「ハッシュとして知られているがPerlでは連想配列と呼ぶ」なんだよ >>267
自己紹介なんかしとらんよ
ハッシュで恥かいたのはおまえだけだ
技術板でねらー語だけのレスしか
できなくなってる惨めなザマ晒してろ std::setw は例えば整数 1 つ出力すると設定がリセットされますが std::setprecision
は持ち越されますよね
この辺の法則性というか思想みたいなものってありますか?一々調べるか試すかしかないですかね マニピュレータはストリームオブジェクトの状態を永続的に変えるのが基本的なコンセプトのはずだけど
なぜかsetwだけ例外で当初から叩かれてる
iostreamは色々と設計がいいかげんだからそういうものだと思って付き合うしかない >>286
リセットというか厳密に言うと operator<< (または operator>>) のオーバーロードの内で width(0) を呼ぶことになっているものがある。
他に勝手に状態が変更されるものは書かれていないっぽいので例外的な処置だなぁ。 > 自己紹介なんかしとらんよ
> ハッシュで恥かいたのはおまえだけだ
> 技術板でねらー語だけのレスしか
> できなくなってる惨めなザマ晒してろ
でっかいブーメラン刺さってんぞw >>272
語るに堕ちるとはまさにこの事。
おまいの主張なら、
Perl has three built-in data types: scalars, arrays of scalars, and hashes.
と書かれていなければならない。 >>291
まだ恥かくの?
とりあえず>>278にレスしてから出直してこいよw >>292
単純にhashのほうが短くて書きやすいからじゃないの? >>294
まあ理由としてはそれもあると思うよ
Perlでは連想配列をハッシュと呼んでいるという結論は変わらんけど HDDを指さしてメモリと言うやつが実在したけど
アレと同じだな >>290
だから何?
既出リストとチェックサムを混同していた
恥ずかしい恥ずかしい「自称技術屋」さんよ どうでもいいのは十分承知
スレ違いも痛感してる
comp.lang.perlへの、とあるオッサンの投稿
https://groups.google.com/g/comp.lang.perl/c/NyYms98cjAY/m/BsGQNfVSZz8J?pli=1
> Doing linear scans over an associative array is like trying to club someone
> to death with a loaded Uzi.
> Larry
associative array( ー`дー´)キリッ
はいわかってますすみませんでしたこれで終わりです >>301
> 既出リストとチェックサムを混同していた
それこそ誰と「混同」してるんだよw
だから何?とか言う前に言う先を見直せよ >>287
>>288
マニピュレータはそんなに色々使ったことあるわけじゃなかったんですけどたまたま setw が例外的な立ち位置だったんですね、ありがとうございます! 言ってもない事で言いがかりつけてきて
> あー、何のことかガチでわからんのね
とか言われても...
基地害に絡まれたことしかわからんw とぼけられることは抜け目なくとぼけるね
見苦しさは1ミリも減らんけど 本質が解ってないから誰かの言い間違いや嘘を
完全に信じてしまいドヤ顔で他人にひけらかすやつが
配列はハッシュと強弁してるだけ
結局みんな匙投げたwww 公式ドキュメントを誰かの嘘や言い間違いとか言うアホ
なお>>278にはレスできないのでガン無視してるのが草 読んでないけど、配列は誰が何と言おうと断じてハッシュではない operator[]できりゃ配列 VS 組み込み配列以外認めない
ファイ! >>315
引っ込みつかなくなって配列と連想配列の違いなんてどうでもよくなってるんだろw
>>317
その方向に必死に軌道修正してるのかもね 配列とは有限の連続した区間の整数と
その整数に対応する数学的に導けるとは限らない値を
関連付ける辞書だ
ハッシュは任意の整数列から数学的に導かれる値だ
誰が何と言おうとどうにもならない違いがある それはC限定の狭い理解だ
本質的にはメモリそのもの ポインタと言えば C言語以来だが、対象の型を宣言するし
最初からポインタ配列なんてのもあるし、そこに優劣は無い >>319
誰も同じなんて言ってないぞ、頭大丈夫?w >>323
おまえさん誰だ?
とぼけるやつとは話にならんなあ >>324
> おまえさん誰だ?
なにとぼけてるんだよw
> とぼけるやつとは話にならんなあ
確かにな WindowsライクのOS、ReactOSで見つけたハッシュの実装例:
https://github.com/reactos/reactos/pull/4916/files
見ればわかるように、ハッシュ関数は自分で作れるんだぜ。 unsigned hash = 0;
for_each(container.begin(),container.end(),[&](auto x){hash += x;});
これでもハッシュには違いない
衝突耐性の制約がなければ自作なんて誰でもできる >>325
一緒やで
切り刻んだ牛肉の料理がハッシュドビーフで、オブジェクトを切り刻んで固定長の値にするのがハッシュ関数や 程よく刻んで一定長の値になるから
分類キーにしたりするんだろ? >>322
ポインタ配列??? おまえは何を言っているんだ? 配列やポインターの指してる中身が何かは今関係ないんだがなぁw ちなみにJavaならハッシュって言うと
java.util.Hashtableよりも
java.lang.Object#hashCode()の話に聞こえちゃうよね(;^ω^)
あとどんな型でも配列にできるんだから
ポインタの配列を「ポインタ配列」などと区別して呼ぶのは珍妙よね
>>325
ココイチのハッシュドビーフうまいよね >>335
> ポインタの配列を「ポインタ配列」などと区別して呼ぶのは珍妙よね
文字配列とか整数配列とかも珍妙かね? 配列の要素が何であろうが配列は断じてハッシュではないことは微動だにしない >>320 で
どさくさに紛れて「配列ってポインターの劣化版だろ?」
という戯言があったから反応しただけだよ >>339
そうか、同じではないのか
で? 配列はキャッシュなのか? どうなんだ? はっきりしろよ ハッシュテーブルの実装に配列を使うのはごく普通のことなので「∃配列 ∈ハッシュテーブル」とは言える。
それを縮めて「配列がハッシュ」と表現する程度のことは文脈によっては自然言語的にはまあ珍しくは無い程度のもんだろ。
よくない表現だとは強く思うけどもあり得ないというほどではないんじゃないの。 ( ;・`д・´)ナ、ナンダッテー!!(`・д´・(`・д´・; )
終わりかけたに見えたスレ違い展開に
ここにきてキャッシュが参戦 まさか餃子がこう来るとは思ってなかった
見損なった 繰り返すけど良くはないよ。
良くはない言い回しだけど自然言語ではその程度のブレは有るものなんだから
ある程度は前後の状況で察していくしかしょうがないだろう。
まあ今回は察した結果として最初に言い始めたやつはなんか勘違いしているっぽくはあるとは思うけど。 キャッシュがわざとなのかハッシュを間違えるほど取り乱してるのか判断できない...w あ、言い間違えてた
キャッシュじゃねえハッシュだ
すまぬ >ALL >>341
C++の配列はハッシュと全く別のものですよ。
混同しないほうが良いです。 >>348
混同してるのはお前を含めた一部の人だけ ハッシュ関数で写像した値をインデックスにとる配列
ハッシュ関数が sha1 とか長い値を返すやつだとちとしんどい いわゆる要約関数と暗号学的ハッシュ関数は関連はあるけど用途が違う
どっちの関数の話かはたいてい文脈でわかるんだがたまに>>354みたいにハッシュという言葉だけに反応する奴が話をややこしくする だから用途の違うものを持って来て「ちとしんどい」とかアホすぎるって話なんだが... 用途の違いとそれを使うときのしんどさは関係ないのでは? 自然言語的にはそれくらいの幅があるってのには一理あるけど、
連想配列をハッシュ関数使ってなくても何でもハッシュと呼ぶのって
ゲームできる機械なら何でもファミコンって呼ぶのと同じくらいハズいよな。 伝わるか伝わらないかで言えばまあ伝わるから、あとは言った人間が恥かくだけの問題
だからそれでいいんだ正しいんだってダダこねれば恥の上塗りするだけ
それで何とも思わないなら別にいいんじゃないの好きに呼べば >>363-364
まだやるの?
誰もPerlでの呼び方が良いなんて言ってなくて単に事実として公式ドキュメントでそう呼ばれてると言うだけの話なのでこんな所で恥ずいとか言ってないで公式に言ってやれよw >>366
perlはハッシュで連想配列を実装してるんだからperl公式がperlの連想配列をハッシュと呼んでも問題ないに決まってるだろ 誰も言ってない
> 連想配列をハッシュ関数使ってなくても何でもハッシュと呼ぶのって
とか言い出した奴にそんな事言われてもw >>366
まだやるのをそのまま返す
配列はハッシュではない
おまえがそこでいくら粘っても覆ることは絶対にない
無駄でかつ迷惑な努力を今すぐやめろ
しつこいぞ貴様 誰が馬鹿なのかなんて一目瞭然なんだから落ち着いてきたところで基地外に餌やるのやめなよ… 役に立つレスは >.277 のみ
Map的なものに対する呼び方で
その人のバックグラウンドが透けて見えて少し面白いよね
map ←C++
連想配列 ←Perl
Hash ←Ruby
Map, Hashtable ←Java
Dictionary, Hashtable ←C# >>370
> 配列はハッシュではない
> おまえがそこでいくら粘っても覆ることは絶対にない
バカは人の話を聞いてないのか、それとも理解できないのか...
>>319
> 誰も同じなんて言ってないぞ、頭大丈夫?w >>373
おまえの戯れ言を聞こうが聞くまいが関係ない
配列はハッシュではない
同じと言ってないのだな
で、配列はハッシュなのか? y/[N] 連想配列をハッシュと呼んでいるドキュメントがあるというだけの話なのに配列とか言い出すアホ乙 >>375
で、配列はハッシュなのか? y/[N] >>378
関係ない
で、配列はハッシュなのか? y/[N] 仮想メモリのアドレス番号それ自体がハッシュの一種であるにより、ただの配列もハッシュであると断言できる >>379
これまでの話に「関係ない」質問をいきなりされてもねw >>381
int a=1,b=1;
このとき&a!=&bで
おまえさんの言うハッシュは不一致だが
a!=bを証明しない 配列がハッシュだってのは、a[0]とa[1]は0とか1っていうアドレスにあるわけじゃなくてaとかa+(型サイズ)のアドレスにいるってことでしょ ハッシュが切り刻んでるって意味なら配列の部分だけみたらそりゃあ切り刻んでる罠 配列がハッシュだなどとぬかす
糖質っぽいのがいて
後進に有害なので排除中なんだよ まあ、別言語の用語を不用意に持ち出すのが良くないんだけどな >>363
コピーってゼロックスですか?って本があったな >>391
不用意にというより
あいつはPerlスレでうだつが上がらず
こんなところへマウント取りに来た
ヘタレの中のヘタレだろw あたおかの論理を分かろうとしても無駄だ
何でC++スレがタゲられたのか俺もわからん そりゃPerlでの連想配列の呼び方の話に
> で、配列はハッシュなのか? y/[N]
なんて言ってもない事で絡まれたら逃げるわなw スレチの話題を持ち込んで散々引張っといて
このヌケサクはなに言ってんだ そう言うのは糖質でとんちんかんな
> で、配列はハッシュなのか? y/[N]
みたいなこと言うやつに言ってくれよw そういうこと言い出すのは反論できない白旗にしか見えないよw 配列がハッシュかどうか答えに窮してんのおまえじゃんw
はい/いいえのどちらでもバカにされんの確定してて 自分の身の丈より高い評価を貰おうと思うな
バカにされるようなこと言ったんだから
まず当たり前の結果を受け入れろ >>404
> 配列がハッシュかどうか答えに窮してんのおまえじゃんw
配列がハッシュなんて言ってる奴はお前しかいないが?w ハッシュというのは、ある種のデータ構造の一種に名付けられた名前で、
検索を速くするためにハッシュ値を使う方式。
unsigned int hash = CalcHash(key);
でハッシュ値を計算し、
Node *p_hash_table[hash];
でデータのリストに即座にたどり着くような方式。
普通に線形検索する場合と比べて検索が劇的に速くなる。
なので連想配列が必ずハッシュ方式であるとは限らない。
また、配列はコンピュータ科学ではメモリー上でデータを連続的に隣接して配置する
単純なデータ構造に名付けられたものであって、ハッシュ構造(方式)とは区別されている。 >>407
訂正:
誤: Node *p_hash_table[hash];
正:
constexpr unsigned int HASH_MAX = 4096;
Node *p_hash_table[HASH_MAX];
・・・
// 典型的なハッシュ方式による検索関数 :
Node *SearchData(string &key) {
unsigned int hash = CalcHash(key); // とても高速にkeyに対するハッシュ値を計算。
Node *pNode = p_hash_table[hash]; // 同じhash値に属する全てのNodeのリンクリスト
while (1) {
if (pNode->key == key) {
return pNode;
}
pNode = pNode->pNext;
}
}
テキトーに書いたのでまだ書き間違いが残っているかも知れないが、大体こんな感じ。 >>408
[補足]
連想配列に良く使われる方式には、大きく分けて二つ有る:
1. ハッシュ構造 >>408 参照。
2. バランス木(赤黒木、B木(2,3,4木など)、AVL木)
C++では、
1は、map、set、multimap、multiset
2は、unorderd_map、unorderd_set、unorderd_multimap、unorderd_multiset >>406
俺は言ってない
おまえに聞いてるんだよ
答えらんねーの面白がっておちょくってんのw
もがくほどSっ気を刺激するだけだぜ >>409
逆じゃね?
map、set~が2で、unorderd~が1じゃないの? >>411
Yes。
最後は逆だった。つまり正しくは:
1は、unorderd_map、unorderd_set、unorderd_multimap、unorderd_multiset
2は、map、set、multimap、multiset >>410
言ってないの?
では何のためにいきなりそんなとんちんかんな質問したんだ?w
で、俺はNoと答えるがそれでどうなるんだ? >>407
>ハッシュというのは、ある種のデータ構造の一種に名付けられた名前
みなここの部分に賛同できなくて議論になってたんでないの?
あとハッシュ構造ってあなたの造語? >>414
MD5などのハッシュとハッシュ法の役割や目的が結構違いまっせ。
前者はデータが改竄されてないかをチェックするために用い、
後者は検索・探索の高速化のために用いる。
恐らく、もとは後者から用いられ始めたのだと思う。知らないけど。 >>227が最初だからおまいらもう1週間もやってるんだなw
スレの途中を読む気もしないので論点も把握してないのだが
C++にはstd::hashがあるので用語は厳密に使う必要があるとは思う >>413=247
さっさと謝ればこんなに恥かかずに済んだのになw >>418-419
>>227は俺じゃねーしそもそも>>231で当人謝ってるのに今更そんなもんだしてきて恥ずかしくないのか?w
で、連想配列の話はもういいんだな
なら話はもう終わりだろ そう来ると思ったよ
わかりやすい奴だなw
はいはい、別人なんでちゅねー >>421
あれれ?
> はい/いいえのどちらでもバカにされんの確定してて
はどうしたんだ?
Noだから はい/いいえ のどちらでも無いってオチかなw >>422
バカにして欲しいんなら別人のふりやめろよ
そんな誠実さは持ち合わせてないから
とぼけてるんだろうがな
予想どおりのクズで却って安心してるぜ もうハッシュの話はお腹いっぱいだから打ち止めようぜ >>424
あらら、話誤魔化すのに必死やねw
もう他人のフリって言い張るしかなくなってて草 ハッシュのおかげで今週は皆楽しかっただろ。
ちゃんとお礼言っとけよ。 >>416
英語の辞書でhashを引くと、「細切れ」「細かく切る」と出てくる。
これは、検索を高速化するためのHash法のHashテーブルが細かく切って
データを格納していることと対応しているようだ。
つまり、Hashという言葉の由来はこのHash法から来ていると推定できて、
Hash関数や、Hash値という言葉もHash法由来のはず。
だから、MD5などのHash値は、Hash法よりも後発のはず。
つまり、Hashというのは、もともと「Hashデータ構造」に対応していて、
MD5などの値を「Hash値」と呼ぶのは「あとづけ」と考えられる。 >>433
[補足]
何が言いたいかというと、もともとHashという言葉は、Hash法由来で、
Hash値という言葉も、Hash法から来ていて、
Hash値やHash関数が先でHash法が後、ということ「ではない」。
Hash法を実現したいために、Hash値を求める方法が工夫された。
Hash法 ---> Hash 値 (by Hash関数)
が正しい起源。
もう一度言う、Hash値を使っているからHash法なのではない。
Hash法を実現するために作る値がHash値。 >検索を高速化するためのHash法
しかしねえハッシュは本来は実用的なメモリ使用量でメモリに乗りきらないサイズの集合の要素を取り扱うためのしくみなのだから、
入力集合の全単射写像ならハッシュにする意味が無いのだから、
検索を高速化する用途の方が後付けなのだから、 ウィキの冒頭にあるようにハッシュというのは検索というよりは区別のためのしくみなのだから、
MDとかSHA-1とかの方こそが本来の意味でのハッシュなのだから、 キャッシュメモリもキャッシュメモリに収まりきらないデータをキャッシュメモリに収めるためにハッシュなのだから、 Perl のハッシュは、もともとは連想配列 (associative array) という名前で呼ばれていましたが、
この名前は長すぎるので、1995 年頃に、Perl コミュニティの中でハッシュ (hash) と呼ぼうということになりました。
Perl5 の時代からはハッシュと呼ぶことになっています。
ハッシュという名前は、連想配列の「実装」に使われるハッシュテーブル (hash table) に由来しています
以上、あくまでもPerl コミュニティの話で、他のコミュニティで流用したら、こんな風にひと悶着起こすわけです いやしつれいキャッシュメモリのハッシュ利用は検索のためやなサーセン;;; どういうことかというとxの検索ではxそのものが取り出されねばならないからxのハッシュはxの検索を利用するユーザーからは見えないから脇役
(別段ハッシュを使わない検索手段で実装してもユーザーにはそれはわからない
一方MD5とかSHA-1とからは長いデータが実用的に無視できる確率でしか衝突しない短いハッシュになるというのがウリなので
MD5とかSHA-1を利用するユーザーはMD5とかSHA-1とかのハッシュそのものを目の当たりにするという違いがある、
というしくみ、 >>437
>検索を高速化する用途の方が後付けなのだから、
Hashが「細かく切る」という意味なのだから、その説は何かおかしい。
細かく切ることによって検索を高速化したものがHash法なのであって。 >>444
Wikipedia英語版のHash tableの項目を見てみると、
The idea of hashing arose independently in different places.
In January 1953, Hans Peter Luhn wrote an internal IBM memorandum
that used hashing with chaining. Open addressing was later proposed
by A. D. Linh building on Luhn's paper.[7]: 15
となっていて、「hashing」がhash tableの概念をそのまま対応していると
考えられる。hashingのアイデアそのものがhash tableのために生み出されたようだ。 >>446
JSでは、
a[key] = val
でハッシュ法を使ったデータに書き込めるから形式的に配列と同じになっているが、
「アルゴリズムとデータ構造」では、ハッシュ法は配列とは完全に区別されている。 ハッシュはキー長固定が前提だけど、配列は(概念的には)固定長前提では無いので、この2つを同一視するのは無理がある。
そもそも配列にキー衝突の概念無いだろ。
配列の場合、キーが異なれば衝突しない。 >>452
自己フォロー。固定長は用語がおかしいね。
キーの要約くらいの話か。 >>427
いじめて欲しければと言ったろ
別人のふりをするのは構わんが
いいか? 配列はハッシュじゃねえぞ
わかったな? >>456
なぜか
> いいか? 配列はハッシュじゃねえぞ
と言う>>227以外の誰でも知ってることを必死に布教してるらしいw >>452
数学的概念としては、独自に同一視して理論を展開することも可能だが、
そもそも、配列のa[idx]はマシン語の1命令でアクセスできて、1クロックなのに
対して、ハッシュの x[key]は、150クロック〜数千クロック程度かかる。
(少なくとも後者はCPUで1命令(1クロック)では処理できない。) そもそもメモリーアクセスが1クロックでできるかどうかは状況によるしハッシュの計算に150クロック以上とかどこから出てきたんだ? >>459
配列の場合、要素のサイズが任意バイトの場合は、一般には明示的な掛け算が必要だから
1クロックではなかった。
スマソ ハッシュはキーがぶつかった時にネストして候補を洗ってく時間がかかるから一意に150クロックってワケでもない Pythonで経過時刻を測る場合、以下のような方法を使いますが
C++でPythonと同じ計測手法を使うにはどうしたら良いですか?
import time
startTime = time.time()
nowTime = time.time() - startTime
print(nowTime) >>465
Windows限定で使用する予定です。 boost::timer::cpu_timerとか? >>467
C++ 関係ないけどパフォーマンスカウンターでggrと良いんでは? >>460
全然関係ないんだが
鼻で笑えないのか? OpenMPの一部であるomp_get_wtime()がじつはパフォーマンスカウンタと同じ精度……
ポータブル…… >>460
keyが10文字の文字列の場合だと大体そんなくらい行くであろうと予想したが、
もうちょっと速い場合もあるかも知れない。 >>463
要は、JSなどで配列とHash法が同じ書き方が出来るが故に、Hash法が
「配列」みたいには高速ではないということを知らない人が居るのではないかと
思って書いただけ。
x86系の場合、配列は、要素サイズが1,2,4,8の時はa[i]がマシン語の1命令で
1クロック、それ以外の一般サイズだと2命令で、今のCPUだと、
4クロック〜20クロック程度。
ハッシュ法だと、keyが10文字の文字列の場合で、最低でも、まあ、100クロック位
はかかると見ておいたほうがいい。最高だと上限は無いが、まあ、数千〜数万
クロック程度になると考えた方がいい。
これは、マシン語まで見たときの常識的な間隔。 マシン語の1命令で1クロックって、いつの何のCPUだ 0 以上 64 以下の整数 n に対して 2^n-1 (ビットごとの排他的 OR 演算子ではなく累乗の意味 2**n-1 です)を std::uint64_t 型で返す関数って場合分け無しでスッキリ書けませんかね? >>476
こうかな?
std::uint64_t(-1) >> (64-n) std::uint64_tの加算オーバーフロー時の挙動がunsigned intと同様にwrap aroundなんなら普通に
std::uint64_t foo(const int n) { return ((std::int64_t)1 << n) - (std::int64_t)1; }
で良くねconstexpr的な何かとかでマズい? すまぬ。 >>477 だと n が 0 のときは未定義なのでそれだけ場合分けが必要になってしまうな。
だからといって (std::uint64_t(1) << n) - 1 だと 64 のときが駄目だし、
場合分け無しという条件だと思ったよりめんどいかも? 違った加算オーバーフローの話やなかったorz
シフト演算については
If E1 has an unsigned
type, the value of the result is E1 × 2E2, reduced modulo one more than the maximum value representable
in the result type.
E1 が符号なし型を持つ場合、結果の値は、E1 * 2E2 の、結果の型で表現可能な最大値より 1 大きい値を法とする剰余となる
なので言語規格上は (uint64_t)1 << 64は合法なはず…… 訂正orz
誤: 2E2
正: 2**E2 (2のE2乗)
符号付きの型はオーバーフローで例外を発生するアーキテクチャーがあるから
表現できるビット数からあふれるコーディングは未定義動作か何かやが
符号無し型はモジュロ演算になるから溢れてもおk
と言う印象(記憶モード
※ 個人の感想です >>478
> https://timsong-cpp.github.io/cppwp/n3337/expr.shift
> The behavior is undefined if the right operand is negative, or greater than
> or equal to the length in bits of the promoted left operand.
シフト演算子では右オペランドが (昇格済みの) 左オペランドの幅以上の値だったときは未定義。 std::bitset を経由すれば大丈夫だということを発見した。
std::uint64_t((compl std::bitset<64>(0)>>(64-n)).to_ullong())
これを「スッキリ」といえるかどうかは微妙なところかもしれぬ……。 >>482
わかりた
ではこう汁、
指数 n == (n/2) + (n/2) + (n & 1) ※ 除算は結果の小数以下切り捨て
ので
2**n - 1 = 2**((n/2) + (n/2) + (n & 1)) - 1
= 2**(n/2) * 2**(n/2) * 2**(n&1) - 1
よって
std::uint64_t foo(const int n) {
const std::int64_t x = (std::uint64_t)1 << (n / 2);
return (x * x * ((std::uint64_t)1 << (n & 1)) - (std::int64_t)1;
}
でだいたいおk、 (1llu << (n>>1) << ((n+1)>>1)) - 1 constexpr uint64_t TABLE[65] = {
0x0000000000000000,
0x0000000000000001,
0x0000000000000003,
...
0xffffffffffffffff
};
return TABLE[n]; x86-64の場合
shl reg, clのclは下位6bitしか見ないから
1ull<<nが正しく動いた場合マシン語レベルでは分岐してることになる >>457
今さら知らなかったとは言えなくて
元々知ってた別人になるしかないもんな
それほどまでに恥ずかしいことだからw
# さあ、おまえが別人かどうかの判断は衆目に任せよう (ID:Xj+KmoE3d が天才すぎてつらいので埋め) ところで、C++でも、Javab磴#でも、メモャ梶[不足例外を封竭ォしない風潮bノなっている
ようです。それは、メモリー不足が起きる可能性があるところの、
文字列合成やコンテナ要素追加が簡単に書けるようになった反面、
その全ての箇所でエラー処理をするのはめんどくさすぎるという
事情から来ていると思います。
しかし、テキスとエディタなどで、一文字や一行追加した時にメモリーが確保できない
場合に、「メモリーが一杯です」などと表示することはMS-DOSならよくあったことで、
そのような場合にメモリー不足例外を補足する事は原理的には可能です。
いまや、そのような場合のメモリー不足はほぼ起き得なくなってますが、エラーを感知
しないで本当に良いと思われますか?
もっと進めれば、メモリー不足例外は、商用アプリでも「完全無視」を決め込んでも良いと
思われますか? >>491
携帯SIMを使っているので電波にエラーが生じたらしいです:
誤:ところで、C++でも、Javab磴#でも、メモャ梶[不足例外を封竭ォしない風潮bノなっている
正:ところで、C++でも、JavaやC#でも、メモリ不足例外を補足しない風潮になっている >エラーを感知 しないで本当に良いと思われますか?
良い
どうせメモリ不足になったら有効なことはほとんど何もできない
ただしそのかわり処理の不意の中断から絶対に保護すべきリソースとか絶対動かしたままにしてはいけない処理は
例外安全なクラスで管理して確実にクローズ処理せねばならない
jこれはメモリ不足の状況でも同じで、そういうのはヒープを使わないで書くのが最善やが、
内部でヒープを使うライブラリに依存している等でヒープをどうしても使わざるおえないの場合は
事前malloc()→例外捕捉時に解放、というテクが昔からあっる スタック的な(?)コンテナで、pop_back()メソッドは戻り値が void型で、
つまり、pop したデータを返しませんが、BJ. stroustrup氏によれば、
それもreturn文で要素をコピー(?)する際に、メモリー不足例外が起きる
可能性考慮したとのことです。
どうしてmoveじゃ駄目なのかもし分かりませんでしたが。 >>493
>どうせメモリ不足になったら有効なことはほとんど何もできない
MS-DOSの時、テキストエディタなどではメモリー不足になると、
ちゃんとメッセージを出して、なおかつ、その後もメモリーが無い割には
安定動作してました。 >>489
まだ粘着してるのかよ...
本人だと思いたいんならそれでいいんじゃね?
おれが本人かどうかに関わらずお前が>>231で本人が謝ってるのにしつこく>>227に粘着するクズであることは確定したし
まあもうそうするしかないんだろうけどw >>494
x = queue.pop();
というのを許すキューの仕様だと
とキュー上のx'とそのコピーxが同時に存在するタイミングが一瞬生じてメモリ不足になりかねないという>>494の懸念の他に、
コピコンが呼ばれる時間の無駄がある
xにムーブコンストラが定義してありqueue.pop()をムーブ対応に設計したとしても
ムーブコンストラクタが呼ばれる時間の無駄は相変わらず存在する
最も効率が良いのはpop()するタイミングまでキュー上のオブジェクトの参照を返し、
pop()するタイミングではキュー上のオブジェクトの破棄のみ行うという現行のインターフェース、 >>497
>x = queue.pop();
>というのを許すキューの仕様だと
>とキュー上のx'とそのコピーxが同時に存在するタイミングが一瞬生じてメモリ不足になりかねないという
よく分かりません。できればもっと詳しくお願いできませんか。
キュー上の x' を x に move すれば駄目なのでしょうか?
>xにムーブコンストラが定義してありqueue.pop()をムーブ対応に設計したとしても
>ムーブコンストラクタが呼ばれる時間の無駄は相変わらず存在する
>最も効率が良いのはpop()するタイミングまでキュー上のオブジェクトの参照を返し、
>pop()するタイミングではキュー上のオブジェクトの破棄のみ行うという現行のインターフェース、
なるほど、参照で返すのは効率がよいのは分かりますが、stroustrup氏によれば、moveは
速いと主張されているわけです。
私はmoveより参照の方が効率が良いと常々思っておりましたが。
彼はmoveが大好きなはずなのですが。 >>499
>キュー上の x' を x に move すれば駄目なのでしょうか?
ムーブコンストラが呼ばれる時間の無駄がある(2回目 >>500
>ムーブコンストラが呼ばれる時間の無駄がある(2回目
なるほど、ならば、スタックポインタだけ元に戻して、値は捨ててしまう
バージョンの pop を用意すれば良いだけでは無いですか、今みたいに。 >>501
Strousstrup氏によると、メモリー不足になって例外が生じた場合の
対処が難しい、みたいなことを言っていたと思います。
しかし、moveコンストラクタ/代入を使った場合にはメモリー不足も生じませんし、
moveコンストラクタ/代入は例外を生じさせてはいけない、と彼自身は
普段から何度も言及していたと思うんです。 >>502
仮にstackの要素クラスにコピーコンストラクタしかない場合は、メモリー不足が
生じてstd::bad_alloc 例外がthrowされる場合があるとは思いますが、難しい
とは言ってもそれが生じた場合に対処が全く出来ないとは思えません。
あるとすれば、要素がmoveコンストラクタを持っている場合でも、
try catch ブロックを書くことで、オーバーヘッドが生じる
場合があることを彼は恐れていたのでしょうか。 >>501
ムーブしたかったらqueue.front()が返す参照でキュー上のx'をxか何かにムーブするだけ(※1)で良くね↑?
x = std::move(queue.front());
queue.pop_front();
※1: xやx'のクラスにムーブコンストラの定義は必要
>スタックポインタだけ元に戻して、値は捨ててしまう
>バージョンの pop を用意すれば良いだけでは無いですか、今みたいに。
ムーブするpop_front()と、デストラクタを呼ぶだけの今のpop_front()がどこが同じなのかkwsk、 >>504
マシン語の「pop命令」は伝統的に、スタックポインタを戻すことと、値を読み出すことを
同時に行っていました。
C++の設計では、値の読み出しと、スタックポインタを戻すことが分かれており、命名も
変なのです。
つまり、2つの事を合体させて行なうのが伝統的に「pop」であった伝統や習慣とは
異なる命名をC++はとってしまっているので、心理的に受け入れがたくなっているわけです。 >>506
例えば、Rustのpopは、ちゃんとマシン語の伝統と同じく、
戻り値が読み出された値になっていて、かつ、スタックポインタも戻ります。
C++のはどうしてこうなったのか、と思うように伝統を破ってます。
伝統を知らない人が作ったかのように。 削除と値返却を同時にやるpop()が例外安全的に糞だって話はExceptionalC++に1章割いて載ってたはず
今手元にないけど C++だけでなく、いくつかの言語で、配列にアクセスするのに
push() pop() といった名前の関数があるから、その流れじゃないの
対象はあくまでも配列であって、cpu のスタックとは色々異なるわけだし
そこでどこまでスタックぽく扱うかは、言語の仕様というか設計者のお好みによるというかw >>508
その辺の話をここに書いていただけると幸いです。 >>510
自己レスですが、
https://stackoverflow.com/questions/25035691/why-doesnt-stdqueuepop-return-value
これですかね。
[Q] Why doesn't std::queue::pop return value.?
[A]
・・・
So, whats the difference, pop function could have done the same thing.
It could indeed have done the same thing. The reason it didn't, is because a pop that returned the popped element is unsafe in the presence of exceptions (having to return by value and thus creating a copy).
Consider this scenario (with a naive/made up pop implementation, to ilustrate my point):
template<class T>
class queue {
T* elements;
std::size_t top_position;
// stuff here
T pop()
{
auto x = elements[top_position];
// TODO: call destructor for elements[top_position] here
--top_position; // alter queue state here
return x; // calls T(const T&) which may throw
}
If the copy constructor of T throws on return, you have already altered the state of the queue (top_position in my naive implementation) and the element is removed from the queue (and not returned). For all intents and purposes (no matter how you catch the exception in client code) the element at the top of the queue is lost.
This implementation is also inefficient in the case when you do not need the popped value (i.e. it creates a copy of the element that nobody will use).
This can be implemented safely and efficiently, with two separate operations (void pop and const T& front()). 0〜255しか格納されないことが保証されている変数aがあって
その変数の値を以下のイメージのように判定する効率的なやり方はないでしょうか
a == {8, 9, 12}
aが{ }内のいずれかの値に該当しているかどうかを判定したいです
{ }はあらかじめ定数でもよいです set<int> unko { 8, 9, 12};
if(unko.find(a) != unko.end()) goto hell; >>514
>>515
ありがとうございます
アドバイスから、bool型の配列を用意しておいてaを添え字にすればよいと思いました >>513
BYTE qqq[256] = {};
void init() {
qqq[8]=1;
qqq[9]=1;
qqq[12]=1;
}
inline BOOL IsInQqq(int a)
{
return qqq[a];
} inline bool is_8_9_12(uint8_t a)
{
return 0b0001'0011'0000'0000 & 1 << a;
} いろいろ例をありがとうございます
pascalからの移行で集合型をどうにか再現できないかと試している中での質問でした
pascalの集合型なら[8, 9, 12](8, 9, 12は一例で、本来は任意の値を指定したい)を
直接使えて便利なので多用していました
アドバイスのおかげで比較は近いことを再現できましたが、
それとは別のケースで[8, 9, 12]を直接関数の引数で指定する方法を探しています
引数で指定する際の値の範囲は0〜31を超えることはなさそうなので
ビットを立てた整数を返す、可変長引数を取る関数を作れば良さそうだと思いました >>520
> 集合型をどうにか再現
それが>>517じゃねーの?
> ビットを立てた整数を返す、可変長引数を取る関数を作れば良さそうだと思いました
そういう関数を作れば良さそうだと思います std::bitset<256>も試してみましたが
{8, 9, 12} こういった形式単独で使えるやり方はないかと調べていました std::bitset は unsigned long long を受け取るコンストラクタには constexpr が付いてるので
それより小さいビット数の bitset についてならコンパイル時に計算してしまうことも出来る。 たぶんやりたいのはこういう感じかな。 (想定は C++17 以上)
#include <bitset>
#include <cassert>
#include <climits>
#include <cstddef>
#include <type_traits>
template <std::size_t N = sizeof(unsigned long long int) * CHAR_BIT, class... T>
constexpr std::enable_if_t<(sizeof...(T) <= N), std::bitset<N>>
make_flagged_bitset(T... args) noexcept {
return std::bitset<N>(((1ULL << args) | ...));
}
// 使用例
int main(void) {
constexpr auto table = make_flagged_bitset(8, 9, 12);
// セットしてないところは偽値
assert(table[0] == false);
assert(table[1] == false);
assert(table[10] == false);
assert(table[20] == false);
// セットしているところは真値
assert(table[8] == true);
assert(table[9] == true);
assert(table[12] == true);
} >>524
やりたいことのイメージにすごく近いです
思いもつかない難しい構文で勉強になります
内容を理解して使わせていただきます
ありがとうございました 定数でいいならマクロでやるとか
#include <cstdio>
#define _(i) (1 << i)
int main() {
int b = _(8) | _(9) | _(12);
for (int i = 0; i <= 12; i++) {
printf("%d:%d\n", i, (b >> i) & 1);
}
return 0;
} >>525
念のために繰り返すけど >>524 は >>523 で述べた性質があるので 64 までしか保証されないし、
エラーチェックをあまり頑張ってないので使い方を間違えたときに捕捉されないかもしれない。
あくまでもおおざっぱにはこういう考えかたでいけるだろうというサンプルだからそのつもりで。 訂正
#define _(i) (1 << i)
より
#define _(i) (1 << (i))
のほうが安心 これまでビット演算を意識したことがなかったので考え方を知れて助かります
提示いただいた例から自分でも調査が進められそうでなんとかなりそうです
いろいろありがとうございました >>529
ビット演算より、速度は、>>518が一番速いかも。 一々メモリアクセスが発生して直感的には遅そうだけど オプティマイズされるからなぁ
記述だけで速度なんか分からないよ 多分>>526が一番速いと思う
b と i がレジスタに乗れば最近のプロセッサーならシフトは1クロックだし
>>524は最適化が上手く行けば同じ位になりそう 速度重視なら>>518だろ
メモリ食うけど、つーてもキロバイト未満だし
古いワンチップマイコンとかじゃなきゃ微々たるもん
ハードできる人ならワイヤードロジックって手もある (Cだけど)昔は isalpha や is~ 系のやつはテーブル参照で実装してたのがあった 集合を扱うには std::set を使うのが楽だと思う。
集合を集合っぽく扱える機能は一通りそろってるからたぶん集合型というものに期待していることはだいたい含まれるよ。
Pascal の集合型のことはよう知らんけど。
(一般的に) std::set は二分木で実装されるという都合上、やりたいことによっては性能 (速度) 上の不満が生じることもあるかもしれないけど、
具体的な問題が出る前に先回りして考えてもだいたい徒労だしな。
>>537
実行時にロケールを切り替える必要性からじゃない? >>537
今でもそうじゃないの?
>>520 > 引数で指定する際の値の範囲は0~31を超えることはなさそうなので
と言う条件だからビット演算の方が早いかもって話であって 、-1~255の範囲ならたいていの環境でテーブル引くのが最速だと思う >>535
テーブル参照はキャッシュが絡むから
単純ではない 0〜255を格納する方は定数でしか使わないので>>518のやり方にしました
0〜31くらいまでしか使わない方は、変数に格納された任意の値の集合を
そのまま引数に渡したり、積集合や差集合を求めるのを想定しています
確かにstd::setがその用途ですね
速度が遅そうで敬遠していましたが、実際にはこれがボトルネックになることはないと思います
initializer_listと合わせれば、ほぼPascalと同じ使用感でいけるので、ビット演算のテクニックは
引き続き研究しつつ、いったんstd::setで実装しようと思います >>540
キャッシュの話になると本当の速さがなかなか分からなくなってくる。
(CPUアーキテクチャやその他の処理の仕方に依存してしまうし。)
キャッシュがある CPU において、キャッシュミスが発生した場合は、
>>526の方が速いであろうと予測はされる。
そもそも、キャッシュの働きが弱いラズパイPICO、Arduino、ESP32 などでは
恐らく>>518 の方が速い。
そもそもシフト演算がシフト量に比例して遅くなるマイコンもあるだろうし。
Z80や8086はそうだった。
x86、x64の場合、
この関数を使うループの中で、他の目的のためにメモリーを大規模に使った場合は、
>>526の方が速いが、沢山メモリーを使わなかった場合は、>>518の方が速い。 std::setは集合演算が思った使い勝手ではなかったです
>>526と列挙型を組み合わせることにしました
長々とスレを消費し申し訳ありませんでした
どのレスも参考になり助かりました >>544
イテレータを受け渡すのがめんどいな。
そのへんは適当なラッパー関数 (または演算子オーバーロード) を定義すればいいんでないの。
たぶんこんな感じにしたいのかな?
https://wandbox.org/permlink/kpYoEhyGaykqITEG >>544
> std::setは集合演算が思った使い勝手ではなかったです
詳しく。 >>545 なるほどめんどくさいな。
よく考えたら contains すら C++20 からっていうのもひどい話よな。 >>545
ありがとうございます
いろいろ知識や考えが足りませんでした
おかげ様で理想形に近づけることができました
std::set<T> operator*(const std::set<T>& x, std::initializer_list<T> init)
foo * _(1, 3, 5)
https://wandbox.org/permlink/14GBm1DqQ6iUaRPq まあ、「ザ・男」ってタイプだからな
ケチがディテールにこだわるのもありがち 配列がハッシュだなんて裏も取らずに信じちまうやつもか? テーブルのアクセスに使う添字はインデックス?キー? >>554
まだいたのかよ、よほど悔しかったんだなw 信じてたやつが返事してるな
今度こそ別人ではあるまい HDDを指さしてメモリと言ってたやつのほうがまだマシ
記憶装置という点でそんなに大外れではないからな
配列を指さしてハッシュと言うやつは
アメリカザリガニを指さして飛行機と言うようなもんで
どうやっても擁護不可能 ここは技術板
配列とハッシュを混同すること以上の恥もクズも存在し得ない 本人謝ってるのにしつこく絡むのは技術云々の前に人としてどうなの? だれも謝罪してないし、配列もメモリマネージャーからみればハッシュだし >>564
> ただ今勉強中で頓珍漢なこと言ってしまった、すいません
クズにはこれが謝罪に見えないんだな... EASTLは、unordered_mapに相当するクラスを独自実装しhash_mapと呼んできた経緯がある
Perlの専門用語が他言語に持ち込まれた分りやすい例といえるだろう >>565
何? 謝罪したらこんなに恥をかかずに済んだってとこに、まだすがりたいの?
そりゃそうだろうね、技術板で最大の恥をさらしたんだからwww
おまえ悪態つきすぎたんだよ、こっちも悪意に満ちた対応するからな
もう覚悟するしかねえんだよ、おまえw C++使いは、その程度のことで粘着しない。
なぜなら、C++使いは爺だから。 unordered_mapはハッシュを使うというだけで、それ自体がハッシュだという主張は誤り
好意的に解釈してもデータメンバと継承を混同するようなもの まだハッシュ言ってるのか
Parl界隈で使ってる言い回しなんだねこのスレで使うなら合ってなかったねで終わる話やろ 経緯を詳細に見る気もしないんだが話は展開していないし
執着の仕方が常軌を逸していると思う
初出は11/24(>>227)だよ! 2週間 粘着自体は無視スルーすれば良いからどうでもいいわ
それより将来鯖ログ開示されたとき
誰と誰が自演だったかの答え合わせはしてみたい >>576
このスレでじゃねえよ
配列とハッシュは本質が異なるものだ
>>319 >>383で根本的な説明している >>576
> Parl界隈で使ってる言い回しなんだねこのスレで使うなら合ってなかったねで終わる話やろ
それを言ってるならまだ分からないでもないけど 配列 ≠ ハッシュ なんて本人謝ってるのにしつこく絡み続けてる
そんなことでしかマウント取れないんだろうけどマジでなんかの病気だと思うわ >>579
じゃあParlスレでは適切だったねでもいいよ
皆お前さんの言ってることぐらい分かってる 謝るのに>>313のような態度で許されるとでも思っているのか そもそも >>313 は Perl での呼び方の話で 配列 ≠ ハッシュ の話じゃないから謝罪なんてしてない
わざとなのか混乱してるのか知らんけど病的なのは間違いない >>576
そこにPerl界隈でも使ってないとか言う奴が現れて無駄に反論を呼んだ。 今日はParl Harbor攻撃から81年目に当たるらしい >>590
とりあえずそれはなんとか収まったけどその後 配列 ≠ ハッシュ 君が粘着しだした 煽り耐性なさすぎなハッシュ君
ちょっとカマかけると元気にお返事しやがんのw
終わりにしたいなら反応しなきゃいいのに
わざわざ出てくるマゾ野郎w ハッシュの話をするやつはコテハン付けろ。NGするから。
コテハン無しでハッシュを話題にするのは禁止な。 カマなんてかけてもないのに頓珍漢レスしてるキチに言われてもねw 反応してる時点でおまえ悔しさがにじみ出てるからw
こっちは誰が何と言おうと絶対に揺るがない基礎理論に基づいているから安心してアホにできてオモロイだけ 「C++」が「Java」を抜いて3位に--12月のTIOBEプログラミング言語ランキング - ZDNet Japan
https://japan.zdnet.com/article/35197053/
Liam Tung (Special to ZDNet.com) 翻訳校正: 編集部 2022-12-07 11:32 多次元配列クラスのSTL入りもまだなのにAIwwwwwwwwwwwww >C++の人気が高まる一方で、Javaの人気は低下している >>600
Objective-C(29位から19位に)
みたいな不思議ランキングなんだから、あんまり意味無いんじゃない? >>601
したくないけどする必要があるときには C++ くらいの機構があるとやりやすいんじゃろ。 知らんけど。 欧米の知的な人たちの間でC++が流行ってるんだろ。 したくないというポイントはだいたい稼げるところだな まぁゲーム開発はいつまでもC++だからなぁ。ついでC# UIはその時の流行りの言語で書くけど戦術ロジックだけは絶対にC++で書きたい C#って、むしろ大規模になって来ると意味不明なエラーが出て破綻しないか? C#が悪いわけではないけど、メモリー解放とかルーズにしたままある程度コード書けちゃうからね、、、
大規模になってくると無頓着だったメモリー解放が火を吹く感じはある
C++はそんなルーズな書き方してたらすぐ破綻するから、そういうコードは多くないけど初期の実装には多くの時間がかかる感じ c#のプロジェクトはなんか疎結合になっとらんこと多いわ プロジェクトを分割しようとしてもどうにも分離しきれない絡み合った部分ってあると思うんよ。
そういうときは機能別に分割するというだけではなく絡み合った部分は絡み合ったものとしてレイヤとして切り分けると上手くいく。
面倒くさいところは一か所に押し込めて横に切る感じ。
C# のプロジェクトはレイヤで分ける意識が希薄で縦割りばかりするので分離しきれない結合が全体にうっすらと残ってる感じ。
密結合というほどではないけど全体にうっすらなので、面倒くさい箇所が一か所にまとまってるよりしんどい。
というのが私の印象。 C# のことはあんまり知らんけど。 https://ideone.com/gopFXn
なんか100回転してから落とすコード書いたはずがヘンな事になってる。
間違ってたかな?向こうのバグかな?? DのUpdateみると1000ms待たないと終わらないように見えるけどそれはいいの? >>614
トップダウン、ボトムアップ、両面から書いていったとき、それが出会うところでグダグダなその場しのぎのコードに書かざるを得ない経験はありますね #include <iostream>
int main() {
const int i = 1;
++*const_cast<int*>(&i);
std::cout << i;
}
何が表示されると思う?
違法?合法?
https://wandbox.org/permlink/57h9V6JX7fJes663 >>618
const なオブジェクトに書き込むのは許されない (未定義) が型の上で const を外すだけならアリ。 つまり ++ を除けば合法だが ++ のせいで違法。 int main() {
const int i = 1;
int*j =const_cast<int*>(&i);
*j=2;
std::cout << &i<<" "<< j<<std::endl;
std::cout<<i <<" "<< *j;
}
https://wandbox.org/permlink/DC1E3ycea3UtdBAI
0x7ffc53e76e1c 0x7ffc53e76e1c
1 2
上のやつちょっといじってみた
アドレスの値同じなのに値違うんだけどなんでなんだろ そりゃ未定義動作だもの
鼻から悪魔が出なかっただけありがたいと思え その処理系ではconst_castはコンパイラをごまかす宣言ではなく&iというオブジェクトを作ってるんだろう 多分
const int i = 1;
を受けた最適化の結果、
std::cout<<i
が
std::cout<<1
という意味のコードになったとかじゃないの
逆アセして調べると良い あるいは真にiの値を見たいのなら
...(前半は同じ)...
auto *p = (volatile int*)&i;
cout << i << " " << j << endl;
みたいにするとか?
※ 個人の感想です まつがえたorz
あるいは真にiの値を見たいのなら
...(前半は同じ)...
auto *p = (volatile int*)&i;
cout << *p << " " << j << endl;
みたいにするとか?
※ 個人の感想です 未定義動作をどうしようとコンパイラの自由なんだからそんなもの調べたってしょうがない
ちゃんと書けばいいだけのこと 既に
std::cout << &i<<" "<< j<<std::endl;
により&iとjが同じ値であることは示されてる
auto *p = (volatile int*)&i;
これでも同じアドレスとして解釈されている(試した)
きっとconst_castに限らずconst領域のアドレスを解釈する時点で
ここのコンパイラは別領域を確保するんだな そのcoutに出してるコードも含めて未定義動作なんだから出力されるゴミ文字列には何の保証も意味もないぞ
だからちゃんとやれ >>629
↓の間違いなのでは……
std::cout << &i<<" "<< &j<<std::endl
これが同じ値になるのなら、iとjが別の実体という仮説はむしろ棄却され、
鼻から悪魔が出たか、さもなくば>>625の説明ぐらいしか残らない >>631
jの型はアドレスint*やで
iと&iが別実体と解釈されてないとこの処理系の挙動は説明できないよ >>632
左様かスマンカッタorz
今神のお告げがあったが多分
>iと&iが別実体と解釈されてないとこの処理系の挙動は説明できないよ
というのは
>変数iとcout << の引数としての定数1が別実体と解釈されてないとこの処理系の挙動は説明できないよ
と考えたら>>625と同じ…… >>633
iが最適化後定数だろうとconst変数だろうと&iについての説明が必要だし
>>625を否定してるわけじゃないよ
>>625のうえで&iがどう処理系で実装されているのかという話 未定義動作ではいおしまいは思考停止では?
コンパイラの実装を考えてみるのも面白い ゴミ捨て場の汚物の配置を面白がる趣味もいいけどそれで宇宙の真理を読み取ったとか言い出されても困るんだわ 特定のコンパイラの挙動が知りたいなら逆アセしろ
仕様が知りたいなら未定義動作
と言うだけの事だろ 未定義踏んで、たまたま望む動作だった場合に、それを放置するのは危険すぎる 前後の状況との組み合わせでも結果が変わったりするから短いコードで試しても
そのコンパイラでの挙動を知れたとは言えんし……。 挙動を考えるというか思想とか背景を考えるのが面白いんだよ
組み込みじゃconst領域は物理的に変えられない場合があるからって
余計な事考えちゃったけどたしかに>>625だろうなって vector<string> v; の vを辞書順でソートした場合、string自体はメモリ上に
連続して並ぶが、肝心の文字列バッファは free store 上でバラバラに離れた
位置になるからキャッシュ・ミスし易くなるね。
stroustrup氏はリンクリストがキャッシュミスし易いと言って馬鹿にしていたが、
実際には動的配列(vector)でも大差は無い。
なお、リンクリストでキャッシュミスし易い典型例がソート後の全巡回ループ。
そしてその場合、vectorでもstringのようなメモリ資源ハンドルの場合は
キャッシュミスが免れない。 >>642
[補足]
そもそも、C++はcopyの代わりのmoveによる高速化を自慢しているが、
それが意味を持つのはstringのようにfree storeのメモリをポインタで持っている
ようなクラスである。
このご自慢のmoveが良く効くクラスTのvector<T>をソートした場合、
free storeの本当の中味のアドレスはソートされないまま。
なので、vectorを全巡回する時には、アドレスが飛びとびになり、キャッシュミス
が起き易い。 >>642 うんうん。リンクリストにするとキャッスミスし易さがもう少し悪化するね。 >>644
この例の場合、vectorをlistに変えてもあまり悪化しない。
なぜなら、stringとその文字列バッファが近接したアドレスのfree store
上にallocateされていると期待できるから。 >>645
[補足]
list<string> v2; の場合、push_back すると、
p1 = new string;
相当の事が実行されるが、p1 の内部の文字列バッファも、string のコンストラクタ
の中で
p2 = new char[N];
のようにして free store から確保される。
確率的には、p1 と p2 は非常に隣接したアドレスになっている可能性が非常に
高い。
その結果として、p1をアクセスした直後にp2にアクセスしてもキャッシュミスは起きない。
その結果、vector<string>とlist<string>のソート後の全巡回でのキャッシュミス回数は、
ほぼ同じ。 >>645 そうだね。悪化するのは少しだけだね。
おや? >>642 ではバラバラに離れてキャッシュミスしやすいと言っていた文字列バッファが
リンクリストの話になると近接するのかい?不思議だねぇ。 典型的な用途ではsmall-string optimizationで大部分が連続になるでしょ
リンクリストにその恩恵はない >>647
>おや? >>642 ではバラバラに離れてキャッシュミスしやすいと言っていた文字列バッファが
>リンクリストの話になると近接するのかい?不思議だねぇ。
ソートしたときには、stringと対応する文字列バッファは意味論的には
くっついている。だから、「対応している」両者は隣接しているんだ。 >>649
[補足]
vector<string>をソートすると、stringの「箱」が新しく確保されてしまうので、
中身だけがmoveされるので、stringと対応する文字列バッファは「離れ離れになる」
list<string>をソートすると、stringはアドレスは全く変化せず、string同士の
リンクのされ方だけが変化するだけだから、stringと対応する文字列バッファは、
メモリー空間上でのアドレスの隣接を維持する。 >>648
それはstringだけの話。
今回はstringを例にとって話しただけで、一般のTではそんな現象は起きない。 >>650
[補足]
vector<string>のソート後の様子:
アドレス
0x0000: st100 ---> buf100 (st100とbuf100のアドレスは離れ離れ)
0x0010: st5 ---> buf5 (st5とbuf5のアドレスは離れ離れ)
st100とst5は隣接する。
ソート時に中身のアドレスだけがmove。
list<string>のソート後の様子:
st100 ---> buf100 (st100とbuf100は隣接したまま)
st5 ---> buf5 (st5とbuf5は隣接したまま)
st100とst5は隣接しない(但し、元のアドレスを維持したまま)。
ソート時には、一切のmoveもcopyも全く発生せず。 いちいちキャッシュのことまで考えて書いたことなんかないですねえ ソート済みならソートの利点を生かしたデータアクセスが主だろうからなあ
まあ最悪値を考えるかアベレージを考えるかはプログラム次第か キャッシュミスが起きるとか
キャッシュに収まりきらない要素数のリンクリストを
全要素まんべんなくアクセスし続ける場合とかの話であって
そうなれば区々たるデータ構造などあんま意味を成さなさげ 配列とハッシュの話を蒸し返すけど、キャッシュに退避したデータを取り出す仕組みはハッシュなので、配列も無意識・無自覚のハッシュといえる プログラムのフェッチもハッシュ、ライトもハッシュ、全てはハッシュに収束するのだ ありていにいえば、他のレイヤーのデータを参照する時にハッシュを使わないと処理速度が落ちてしまうので、いたるところに速度対策でハッシュ参照が実装されているってのがFA 仮にunordered_vectorなるものがあったにしても、それはハッシュではない vectorはそもそもunorderdだろ
setは同じ値を格納できないのだからvectorとは違う 全文字列を結合したものを一括で確保して string_view を操作するのが1番パフォーマンス良さそう >>665
失礼な言い方になるかもしれませんが、あなた初心者ですね
“パフォーマンス”を気にする人はそもそもC++なんて使いませんよ >>666
そんなに苦手だったんか
まあこれから練習したらええよ >>670
vectorがunorderedとが頭おかしいのかって >>669
c++のunorderd_は挿入時に挿入要素のキーによるソートが行われず要素の格納順が実装依存なコレクションに付けられている名称だから、vectorがunoreded_かどうかと言えばyesじゃない? >>675
そういう考え方もあるか
でもiteratorで途中指定してinsertしたらそれ以降のキーと要素の対応全部ずれるしmapと考えるのはどうなんだ ランダムアクセスできるデータ構造でordered_だのunordered_だの定義してもこじつけでしかないし意味薄いんでは そんな事を言い出したらページアウトされてるデータの読出しになるかもしれないからディスクアクセスかもしれないだろ >>680
ところでこの話の発端のhashでないunorderd vector ってどんなものをイメージしてたの? >>673
vectorは連続したメモリ領域に要素を保存し、順番に並ぶことを保証する。
そうやってc配列との互換性を保っているのは常識かと思っていたけど、仕様変わったの? >>686
それで正しいと思うよ
c++のunorderd_/(ordered_)は要素をキーにしてコレクションがソート済みになるかどうかを意味してると考えれば>>673とも矛盾してないでしょ? ordered_配列 ==> 勝手に中身がソートされる配列
が思い浮かぶ >>688
std::multiset なんてのがあるんだな そもそも、ordered かどうかは定義の問題。
まず、mapは、(key,value)を持っていて、keyで検索できる。setは、keyだけでvalueが無いが、
keyで検索できる。setは、mapでvalueをkeyにしたようなもの。だから、以下ではmapだけ
の話をする。
mapやunorderd_mapは、「検索」機能とbegin(),end() を利用した「巡回機能」の
両方を持っていて、巡回を key の大小関係順に巡れるかどうかで、
ordered かどうかが決まる。
バランス木(赤黒木など)を使う方が 接頭辞なしの map、ハッシュ法を使う方が
unorderd_map
前者の場合は、常に自動的に並び替えられた状態で格納される。
一方、そもそも vector は、好きな順序で入れられて決まったキーもなければ
自動的に並び替える機能も持ってないし、orderedかどうかを定義しても
特に意味が無い。そもそも、orderdのvectorが存在し無い。
また、故意に作ってもしょうがない。 ordered, unordered
が書けないヤツが多すぎ問題 >>688
それが大体、「set」や「multiset」に相当する。 >>694
まだ使ったことが無いので書き方が間違ってるかも知れないが、
map<T,V> m;
に対して、
for ( auto &r : m ) {
cout << r.first << ":" << r.second << "\n";
}
で巡ることができる機能の事を言ったつもり。
for ( auto i = m.begin(); i != m.end(); ++i ) {
cout << m[i].first << ":" << m[i].second << "\n";
}
と等価だと思う。
ただし、一度も使ったことが無い。 keyとしてpointerを指定したmapがpointeeで正しくソートできるように
3番目のテンプレート引数にpointerを剥がして比較するless演算子を
以下のように渡します
g++ではm1は-std=c++17では不可ですが-std=c++20だと通ります
m1にはcomparatorの型しか情報を渡しておらず
m1は実装に関しては何も知らないはずなのですが
正しくpointeeでソートします なぜ?
#include <iostream>
#include <memory>
#include <map>
using namespace std;
int main ()
{
using Ptr = shared_ptr <int>;
auto comparator ([] (const Ptr &lhs, const Ptr &rhs) {return *lhs < *rhs;});
using Map = map <Ptr, int, decltype (comparator)>;
// Map m0 (comparator); // -std=c++17と-std=c++20で可
Map m1; // -std=c++17で不可, -std=c++20で可
m1.insert (make_pair (make_shared <int> (2), 2));
m1.insert (make_pair (make_shared <int> (1), 1));
m1.insert (make_pair (make_shared <int> (3), 3));
for (const Map::value_type &key_value: m1)
cout << key_value.first << ' ' << key_value.second << '\n';
return 0;
} 納得しちゃダメだった
ラムダ式の型は実装ごとに異なるみたいですね
以下__cxa_demangleがg++依存だけども
#include <iostream>
#include <memory>
using namespace std;
namespace abi {
extern "C" {char *__cxa_demangle (const char* __mangled_name, char* __output_buffer, size_t* __length, int* __status);}
}
string name_of (const type_info &p)
{
int status (0);
char *tmp (abi::__cxa_demangle (p.name (), 0, 0, &status));
string result (tmp);
free (tmp);
return result;
}
int main ()
{
using Ptr = shared_ptr <int>;
auto c0 ([] (const Ptr &lhs, const Ptr &rhs) {return *lhs < *rhs;});
auto c1 ([] (const Ptr &lhs, const Ptr &rhs) {return *lhs > *rhs;});
cout << (typeid (c0) == typeid (c1)) << '\n';
cout << name_of (typeid (c0)) << '\n'
<< name_of (typeid (c1)) << '\n';
return 0;
}
$ g++ -std=c++20 test.cpp
$ ./a.out
0
main::{lambda(std::shared_ptr<int> const&, std::shared_ptr<int> const&)#1}
main::{lambda(std::shared_ptr<int> const&, std::shared_ptr<int> const&)#2} >>697
> m1にはcomparatorの型しか情報を渡しておらず
> m1は実装に関しては何も知らないはずなのですが
ここが思い込みかと。
ラムダ式のクラス型に比較関数が含まれてて、その内容もインスタンスに依存しないし、
比較方法は十分伝わってるから問題ないということで何も不思議じゃないと思う。 >>701
はい
ラムダ式の型というものを理解していませんでした
型で実装を伝えることができるのは
関数ポインタと大きく異なっていて面白い性質ですね 関数ポインタと書きましたが
関数オブジェクトとの相似で考えると不思議じゃないですね
関数オブジェクトも型で実装の情報を渡しますから
失礼しました >>687
c++のunorderd_/(ordered_)は要素をキーにしてコレクションがソート済みになるかどうかを意味してると考えれば
全然違うよ。標準くらい読みなよ。
Associative containersとUnordered associative containerの本質的な違いはキーの定義。
Associative containersのキーは順序で比較可能でなくてはならず、Unordered associative containerは同値で判定可能でなくてはならない。
ついでに言うと、配列は(記憶に間違いなければ)直接メモリ番地で指定できなきゃならなくて、キー(みたいなもの)も(正)整数でなくてはならなかったはず。 配列の添字がキーだと思ってる人と
配列の中身がキーだと思ってる人
とじゃ会話が成り立たない
実際はどちらもキーではない ねえパパ、バカって何?
簡単なことを難しく言う人のことだよ
う~ん、よくわかんないや 標準の話をするならvectorは連想配列じゃないしorderとか考えるものでもない >>同値で判定可能
同値「かどうか」判定可能じゃないの?
>>配列は直接メモリ番地で〜
意味不明 >>709
>同値「かどうか」判定可能じゃないの?
意味不明。
厳密に言うなら、Unordered associative containerが要求しているのはa == b a != b。
同値「かどうか」とか曖昧な突っ込みで何やりたいの? >>704
なるほどだいたい理解した
つまり最初の話に戻るなら unordered_multivector というものを考えた場合、格納する要素を a == b と a != b が定義されているものに限定して、
最悪の実装を考えると要素の格納方法は vector そのもので良くて要素のサーチは先頭からリニアに a == b をチェックしていくことになり、
unordered_vector ならば要素格納時に a == b なものを除外すればよいというわけだね (使い所が無い)新たなコンテナを考えるスレじゃないと思う
当然Perlのスレでもない C++の配列がordered, unorderedどちらの分類に近いかなら
キーが配列の添字 ==> ordered
キーが配列の中身 ==> unordered >>712
同じ値を除外する必要は無い
集合と違って配列は同じ値を許すのが普通 >>712
>>705
中身とキー(みたいなもの。インデックス・添字)は別物。
あと、標準だと
The elements of a
vector are stored contiguously, meaning that if v is a vector<T, Allocator> where T is some type other
than bool, then it obeys the identity &v[n] == &v[0] + n for all 0 <= n < v.size().
だから、vector にunorderとかmultiとか考えても意味がない。混乱の元だからやめたほうがいい。 >>716
vectorのキーはuniqueでordered
vectorの中身はmultiでunordered
考えるまでもなく自明 vectorにinsertがある
添字はkeyではなくindexでしかない
何にとってorderedであるかはプログラマーに委ねられている 訂正
vectorの添字はuniqueでordered
vectorの中身はmultiでunordered >>711
いや「同値で判定可能」って日本語として意味通ってないじゃん
取れる揚げ足を作った奴が悪いよ
「厳密に言うなら〜が要求しているのは a==b a!=b」も全然厳密じゃないじゃん
a, b が何なのかも書いてないし、operator== と operator!= が定義さえされてればいいのか (a==b) ^ (a|=b) が true である必要まであるのかもその書き方だと分からない ordered ≠ 全順序
== : 同値関係ではない == が同値関係であるとは
a == a
a == b ⇒ b == a
a == b, b == c ⇒ a == c >>697
>m1は実装に関しては何も知らないはずなのですが
>正しくpointeeでソートします なぜ?
結論から言うと、ラムダ式は 関数呼び出し演算子 operator()() を
持った名前なし functor に対応していて、「デフォルト値」で構築
しても機能を果たすから。
[詳細]
ラムダ式は、名前なし functor で、関数呼び出し演算子 operator()() を持った
クラスに対応している。いまの場合、
auto comparator ([] (const Ptr &lhs, const Ptr &rhs) {return *lhs < *rhs;});
は、
class SomeFunctor {
public:
bool operator()(const Ptr &lhs, const Ptr &rhs) {return *lhs < *rhs;}
};
に対応していて、
SomeFunctor cmp{};
で SomeFunctor のオブジェクトを作ってから、
bool b = cmp(lhs, rhs);
とすると比較できる。
故に map クラスは SomeFunctor のオブジェクトをデフォルト値で
初期化すればいいことになるから、ユーザーが SomeFunctor の初期値
を渡さなくて良い。
実際に、mapクラスは、デフォルト値で初期化した SomeFunctor のオブジェクトを
基本クラスのメンバ変数に(実質的に)持っている。 >>696
setクラスは常に大小順に順序を整列し続ける集合としては最高レベルに高速。
検索も挿入もO(N・log N) >>704
いや、ordered_が付かないmapやsetは、順序で並び替えることも定義の一部になっていて、
範囲forで巡ると、挿入した順序ではなく、比較関数で比較した結果に基いてソートされた順序になる。
https://stackoverflow.com/questions/7648756/is-the-order-of-iterating-through-stdmap-known-and-guaranteed-by-the-standard
Yes, that's guaranteed. Moreover, *begin() gives you the smallest
C++
・std::map is a sorted associative container
https://stackoverflow.com/questions/11274978/are-c-stdmapstring-string-ordered
are STL maps ordered?
Yes, a std::map<K,V> is ordered based on the key, K, using std::less<K> to compare objects, by default.
So if I iterate over it, it will iterate with the first insert string first?
No. It will iterate based on the sorted order, not the order that you inserted elements. In the case of std::string, it sorts in lexicographic order (alphabetic order).
If you want to iterate based on the insertion order, you're better off using a sequence container, such as a std::vector or a std::list. >>727
誤: いや、ordered_が付かないmapやsetは、順序で並び替えることも定義の一部になっていて、
正: いや、unordered_が付かないmapやsetは、順序で並び替えることも定義の一部になっていて、 >>702, 703
そういうことやね。
ラムダ式は、関数呼び出し演算子 operator()()を持ったクラスに対応していて、
その演算子が、ラムダ式の中身になっているから、テンプレート引数に
クラスの型を渡すだけで関数を渡せる。
ローカル変数をキャプチャしている場合は、どうなっているか良く知らないけども、 >>726
なんかさらっとオーダー間違ってるし
見逃した
最高レベルでもない
検索も挿入もO(1)なのが存在する >>728
じゃんけん型の場合はどうなるんだろうねえ >>731
ほんまや。正しくは、一回当りの検索や挿入に掛かる時間のオーダーは、
O(logN)
だと思うわ。
>>731
>検索も挿入もO(1)なのが存在する
常にソートし続ける集合でそんなん有りましたっけ? >>733
俺は、紙に書いてあるのを丸覚えてるわけじゃなくて、あたまのなかで
1秒でシミュレーションして自分で割り出してるが、簡単すぎるので、
テキトーに書いてしまう癖が有って、打ち間違える。 int x,y;
auto f = [&x,y](){};
のとき、
fの型は
struct{
int& _x;
int _y;
void operator()();
};
相当だとは思う。
コンストラクタ周りがどういう扱いされてるかはわからん 逆に
構造を知らないでオーダーだけ丸暗記してるようなのがいるとでも思ってる? >>727
key とelementが紛らわしいなぁ。
c++標準は「keyで並び替える」。setはkeyがelementになるので結果として「elementで並び替えたのと一緒」となるだけ。key とelement をしっかり区別しないと擬似問題になるよ。 >>741
「中身はmultiでunordered」の意味が全然分からないから無視したんだけど……
なにこれ? 配列の中身は順序が定義されてる必要はなく
複数の値も取り得る 配列の中身をmultisetのkey,element
配列のインデックスをmultisetの要素のn番目のn
ととらえれば配列はmultiでunordered
配列の中身をelement
配列のインデックスをkey
ととらえれば配列はuniqueでordered
実際はどちらでもない >>744
「複数の値も取り得る」は嘘だろ。
vector<vector<T>>の話? multi : 別の場所に同じ値を入れられる、同じ値を複数個保持出来る 声のでかさが正義だと思っている、どっかの山猿軍団みたいなやつがいるな >>725,730
有難うございます
その理解に至りました
それと>>698の合わせ技で
mapのkeyにポインタを入れるのが随分とスマートになった印象です
using Ptr = shared_ptr <int>;
auto comparator ([] (const Ptr &lhs, const Ptr &rhs) {return *lhs < *rhs;});
using Map = map <Ptr, int, decltype (comparator)>;
Map m1; >>738
ここは、教科書そのままを丸覚えしてるだけの人が多すぎるように感じるので。
教科書に出てなくても、ちゃんと実際に起きるようなことを書くと全く理解できない
人が多すぎるから。 >>747 >>748
multimapの"multi"の意味と違うなぁ。それはmapでもできる話じゃない?
cpprefjpに解説あるから調べたら?
C++ Standards だと22.2.6.4ですな。
(N4849)
An associative container supports unique keys if it may contain at most one element for each key.
Otherwise, it supports equivalent keys.
The set and map classes support unique keys; the multiset and multimap classes support equivalent keys. >>755
「ほぼ全員」というのは「自分は除く」ということかね。
傲慢だなぁ。 >>756
なぜそう思うかって言うと、俺が言ったことがちゃんと通じる相手も存在しているからだよ。
客観的にハイレベルだと思える人には俺の言ったことが通じる。
しかも、この話だと確実に通じると思ったことはちゃんと確実に通じる。
ところが、この板だと結果は惨敗。全く通じなくて、逆にけなされ、馬鹿にされる。 お前も俺が書いたこと理解してないし
俺からみたらお前はアホ >>754
>>745を見た上で書いたんだよな?
だとしたらアホだ >>761
普通に東大生とかなら通じる内容だぞ。
自分で「まともなこと」言ってるかどうか、俺は分かるもの。 >>766
なお、東大生でも理解力が無い人は理解力無いと思う。
本当に頭のいいのは、一部の学科に集中している。
東大以外でもレベルの高い大学なら理解できる人多いぞ。
ここにも東大生は来てるかも知れんが、残念ながら頭がいいタイプの人は来てない。 理解力が無い人は理解力が無い
当たり前ですねwww ホリエモンや高橋洋一も言っていたが、レベルが合わないと話してることが
全く理解されなくて、むしろ馬鹿にされ、阻害されるものなんだぞ。
高橋洋一にいたっては東大に行っても理解されなかったそうだ。
根本的に頭がいい人はそうなる。
日本では特にそういう人を社会から除外するし。 >>772
このスレでは、目に余るものがあって、
そもそも、学級崩壊しているような状態で、まともに議論できない。
正しいことを言ってる人を馬鹿にして、間違ってる子と言ってる人が大きな
顔をして、自分が正しいことを言っているかのような態度をとる。
そもそも議論の土台が出来て無い。
まずは、ホームルームや道徳の様なことから始めなくては。 コミュニケーションってのはコンパイラと違って
言語モデルやその背後にある思考モデルはダイナミックに変化する
それについていけなければ会話は成立しない
更に特定の一つコンパイラを相手にしていれば良いという訳でもない >>774
現実に通じる相手も存在する。
居るところには沢山居るが、日本全体としては少数。
だから、コミュニケーションの問題ではなく、生まれつきの頭のよさの問題だと
俺は理解している。 会話ってのは一人でやるもんじゃないんだよ
双方が相手の頭の中を推定できたときに初めて噛み合う
相手に自分の頭の中を推定しやすいような
手掛かりを上手に出すのも技術のうち >>776
もしかしたら、ネットだと文字が読めてないのかもしれない。
声では理解できるのに長い文書が読めない人が多いらしい。 >>762
>745を見直したけど意味不明だわ。
これは>719
>vectorのキーはuniqueでordered
>vectorの中身はmultiでunordered
>考えるまでもなく自明
の説明ということだよな?
> 配列の中身をmultisetのkey,element
> 配列のインデックスをmultisetの要素のn番目のn
> ととらえれば配列はmultiでunordered
で配列をpair<K,T>[]に限定するような話が突然出てくる。
>712のunordered_vectorに頭の中身が引きずられてない?
そんなにunordered_vectorの話がしたいの? 俺は嫌だよ。
>配列の中身をelement
>配列のインデックスをkey
>ととらえれば配列はuniqueでordered
はかすかに議論の流れに沿っているけど、
>実際はどちらでもない
で放り投げられているから、結論として何を主張したいのかも分からん。
これじゃ「>719はどちらも間違い」という主張にしか見えん。
>745にマトモな結論も主張も無いから、この話がどう>747 >748 につながるかも分からん。
エスパーじゃないんだから、バラバラで繋がりの無い情報を読んでも>762の頭の中なんて分からんよ。
「だとしたらアホだ 」と言う前に、引用レスぐらいちゃんと読み直して補足情報ぐらい書いたら? >>775
そりゃ、有り難くも相手が理解しようと努力してくれているからだろ。
会話で「情報の非対称性」は意識している?
相手がどのような情報を持っているのかを無視して、自分の立場を
ゴリ押しして相手にマウントしようとすれば、そりゃ相手に嫌われるわ。
まあ、相手に嫌われるのが目的ならそれでOKだけど。 ハッシュでないものをハッシュということにしたくてヤダジタ大暴れ
みっともねえな >>713 と >>714 が同じ人間と思えないくらい
>>714 のあほっぷり でかい声出しても人を小馬鹿にしても
それでハッシュでないものがハッシュになるわけでなし
無駄で関係ない努力をし、そのために他人に迷惑が及んでも
構わないという自己中心的なやつ >>768
一人二(+a)役でピンポンしてるだけでは >>778
あまりにも、あまりにもレベルが低い
まるでチンパンジーのようだ >>784
>>778
>745で説明したことにするアホと会話するのは不可能 hashのレスはあんまり読んでいないんだけど、c++標準のhashの話だよね?
c++標準と関係の無いhashをc++スレで持ち出してhash hash 言っているわけじゃないよね?
まさかそんなアホいないよね? いまだにハッシュガーとか言ってるのは何が悔しいのか粘着キチだからスルーでOk >>787
いやC++に限らない一般論としてハッシュとは何が明らかに分かってないやつが暴れてんの 見たところPerlスレ民のほうが
キチガイを追い出すのはうまかったようだな 名前、それ自体がハッシュだよ
ありとあらゆるものが名前を与えられることによって唯一性・独自性を確保する
つまり、人間の脳は万物をハッシュで管理している ほらな
何にもわかっちゃいねえ
乱数や暗号との違いが言えねえぞコイツ c++20のコンセプトとかモジュールとか<=>とか誰か使ってる? <=>初めて知ったけどめちゃ便利だな
うちの環境じゃ使えないのが残念だけど a > b, a < b, a == b を一度に判定するだけの演算子の何がそんな便利やねん!
とおもったらこれ一つ定義するだけで各種比較演算子全部児童生成してくれるのね
なるほどこりゃ便利かも using rel_ops だとスコープ全体に影響でるから使用控えてたけど、operator<=>で全部解決出来るようになったのはいいな 3方があると4方も欲しくなる
a < b
a = b
a > b
unordered
結局戻り値4値の関数を作ることになる 宇宙船演算子……!
ってオーバーロード……!
可能なの……?! >>807
std::partial_ordering返すようにすれば<=>で4方出来るぞ >>808
いや、なにをいってるんだ
そのためのものだろ >>810
それはそうか……orz
a-bのオーバーフロー対策なだけかと一瞬思った…… このスレ見てるとわかるがC++が好きって言ってるやつって知能低いな このスレには周囲に天才と言われる人がいるからそれは違うな あんなやつに褒められても嬉しかねえよってやつに
どう思われようが関係ねーなあ namespace std {
template <class T, std::size_t N>
struct array;
}
みたいに標準ライブラリの前方宣言を自作のヘッダに書くのってやっぱり未定義動作なんですかね? stdに勝手に宣言加えていいのは既存テンプレートの特殊化だけ
他は未定義 >>818
原則としては std 名前空間になんらかの宣言や定義を追加したら未定義ということになってる。
https://timsong-cpp.github.io/cppwp/n4861/namespace.std
その事例も該当すると思う。
条件付きで許されている特殊化はあるが C++20 から制限が強化された。
(従来は条件付きで「テンプレートの特殊化を追加できる」だったのが「クラステンプレートの特殊化を追加できる」に改められている。)
ユーザー定義型ごとのカスタマイズを許したい場面では Customization Point Object (CPO) を
活用する方向性なので特殊化でどうにかする必要もないし制限が強くなることはあっても緩和されることはないんじゃないかな。 そんな堅苦しい事なんて言わんでもええやん?
どんな弊害があるん? >>821 標準ライブラリの変更にあたって、 std に宣言追加しているソースへの影響を考えないといけなくなる。 >>822
リンクで失敗するので修正すれば良いだけでは? 「未定義」ってほどには深刻な問題はないと思うんだよね コンパイラがstdに勝手宣言がないことを前提にしたあらゆる最適化の結果を受け入れるなら別にいいと思うよ
俺は絶対に嫌だから関わらないでくれよ >>825
いやまぁ>>818は俺じゃないので俺も必要性を感じているわけではないけども
具体的に何を恐れているのか分からん >>826
何が起きるか具体的にわからないから恐ろしいんだよ。 >>827
oresamaライブラリの中でoresama名前空間があって
arrayが定義されていたとして
oresamaライブラリとは別のプロジェクトで
oresama::array前方宣言したときに
起こりうることは予想がつくよね?
それがstd名前空間だと動作が未定義だとのことだけども
何が違うのか分かります? >>829
コンパイラ様はstd以下を思うままに特別扱いしてカオスでアドホックな最適化処理をいくらでも入れることが許されてる >>830
>>825も指摘してるけどoresamaとstdの違いはそれくらいだよね?
具体的にどういう最適化をして鼻から悪魔を出すのかな?
まぁそんなことを分かる人はおらんかな... >>831
コンパイラの内部に興味を持って調べたいならどんどんやればいいよ。
詳しい人が増えるならそれはたいへん喜ばしい!
でも、リッチな C++ コンパイラのソースコードを読んで様々な最適化がどう組み合わさるかまで把握するのは
相当に高い技能を持った達人でないと無理なのでこのスレ程度ではなんもわからんと思う。
世の中にはこれを保守している人がいるんだからありがたい話だよな。
私がどこかで見たおぼろげな記憶では標準テンプレート関連の一部で
マングルのルールが異なる (名前が短くなるようにしてる?) というのがあるので
変なことをすると破綻することもあるのかもしれない。 なぜこうもわざわざ未定義動作を踏み抜きたいやつが多いのか コンパイラをナメてるからだろ。
「未定義動作つってもどうせこうなるだろう」という予測が出来ると信じている。
無理なのに。 まあ単なるテンプレートライブラリなのにstdだけを特別扱いして最適化を図るのはちょっとやりすぎな気がしなくもない clangのソースコードはC++プログラムの書き方の勉強になりますね std::arrayってなんらかのusingであることが(コンパイラ側への制限として)許されてたりするんか?
もしarrayの実体がこんな実装だったら
namespase std::__internal {
template<class T, size_t>class array{...};
}
namespase std:: {
template<class T, size_t>using array=__internal<T,size>;
}
勝手にこれ書いたらまずくならんか?
namespase std{
template<class T, size_t>class array;
} >>818
それやると特定のC++バージョン、特定のコンパイラでしか
コンパイルできないコードになりかねないし、
普通に #include <array> すればいいだろ。
それともそれが出来ない理由があるとか? >>832
なるほどマングリング変えられるとリンカーエラーで
しばし悩むかもしれませんね
>>837
これはコンパイルで弾かれるので分かると思います
おふた方とも勉強になりました! 有り難うございます
しかし未定義動作ってほど酷いことにはならないのかなぁと思います
なめてますかね私? >>840
未定義動作と定義されているんだから未定義動作としか言えんだろ。 >>841
未定義動作とはコンパイルもリンクも通って実行できるけど
どんな動作をするか分からない(未定義)ので
事前に分かるコンパイルエラーやリンカーエラーに比べて
「酷い」と表現しました
いわゆる「鼻から悪魔」 >>842
まぁ規格に書かれちゃってるんだからそりゃそうですね もしも「必ずエラーとして報告されるべき」みたいな仕様にしたら std の特別扱いが要るから
標準ヘッダのファイルに素朴に書くだけな実装はやりにくくなるし……。 void InitBoard(void) // 盤を初期化
{
int x, y;
for (y = 0; y < YMAX; y++)
{
for (x = 0; x < XMAX; x++)
{
board[x][y] = 0;
}
for (x = 0; x < XMAX; x++)
{
num[x] = 0;
}
}
}
この処理の無駄を省くコードおしえてください >>843
酷いとわかっているのに
なんでこの未定義動作だけ酷くはならないと思えるの? memset(board, 0, sizeof board);
memset(num, 0, sizeof num); 標準に <iosfwd> あるくらいだし動機はわかるけども
あんま詳しくないけどモジュールはよってことなんかね? 禁止と言われて、そうですかと聞き分ける人と、ゴネる人がいるってことだ。 >>847
>>821からの流れは
実際に「酷い」鼻から悪魔が出る処理系はないんじゃないかな?って問い掛けです
少なくともここのスレではコンパイルエラーやリンカーエラーになる事例は
指摘がありましたが「酷い」ことになる事例は出ていません(誰かもしあれば?)
なぜそう考えるかは名前空間oresamaでは合法で
名前空間stdのみに規格において例外的な規定がなされているからって程度です
>>845のようにエラーが明示的に出ないのも
酷いことにならんのじゃないかなぁと
私が考えてしまうことに貢献しているかも >>846
std::fill を使うのが妥当じゃないかな?
memset でも普通は問題は起きないと思うけど
メモリブロック (バイト列) に対する操作だから board の型によっては
問題が起こることはなくもない。 >>851
そういうことではない
文法的にダブルスタンダードになってるのが気持ち悪い
名前空間stdもoresamaも同じ取り扱いである方が
文法的に美しいって感じているから
実際には最適化のためにstdは特別扱いが規定されている (自分の環境だと)酷いことにはなってないから
未定義踏んでてもOK派?
勘弁してください >>855
煽ってものらないよw 誰もそんなことは書いていない
酷いことになる事例を教えてねってことを書いています
どういうこと(最適化?)を想定してダブルスタンダードにしたのか
動機を知りたくないですか? fill_n(num,__countof(num),0)
上のboardは自分で考えるんだ >>854
自分が作ったライブラリの名前空間に何を追加されても正しく動く (または必ずエラーになる) ように保証してんのか?
各ライブラリごとの挙動に保証していることと保証してないことがあるのは当たり前のことだろ。
お前のライブラリについての保証はお前がするから「言語では」関知しないってだけで、
oresama に何を追加してもよいことが保証されてるわけではない。 >>858
たぶん伝わってないな
以下をユーザが自分のソースに書くのは>>820の言うように規格で禁じられている
namespace std {
template <class T, std::size_t N>
struct array;
}
同じくoresama::ARRAYなるカスタムのクラステンプレートが定義されていたとして
以下をユーザがソースに書くのは合法
namespace oresama {
template <class T, std::size_t N>
struct ARRAY;
}
これをダブルスタンダードで気持ちが悪いと思っている
最適化との説だけども
具体的なことを知っている人がいたら聞きたいな >>846
そのboard[x[][y]はゼロフィルしても良い配列?
盤外に飛び出す桂馬飛びの高速判定テクニックとして実はboard[-1][-2]が壁のコードになっている
とかありそう
※ 全くの想像です
※ 未定義動作と言われても知らそんこの場合アセンブリコードが正しくて速ければええんじゃ
※ この場合2次元配列はやめてカラム数が2のべきの1次元配列であるべき
※ ここまで全くの妄想です 説明が抜けた;;;
board[-1][-2]が壁のコードになるような思想の場合は
board[0..][0..]にも当然盤を取り囲むように壁のコードが配置される >>859
お前のライブラリの仕様はお前が決める、
標準ライブラリの仕様は言語仕様で決める。
そこになんの違いもありゃしねぇだろうが >>862
一行目は違う
oresama::ARRAYの前方宣言が合法なのは
文法で規定されている >>863
No.
許されているのはそのライブラリの設計がそうなっているからで許さない仕様のライブラリはあり得る。 >>864
前方宣言を許さない設計なんて本当にあるの? >>865
すでに >>837 で示されてる。 見かけ上の名前は別名であるかもしれない。
別名ではない実装で書かれていることがはっきりしていて将来も変更されないと oresama::ARRAY について
保証されているならそれをあてにしてもいいんじゃないの。
で、それを保証するかどうかはライブラリを作ったやつの裁量次第。 >>866
誰か突っ込んでくれると思ってた
有難う! namespaceはシンボルの衝突を防ぐためのしくみなのに
後から要素を追加できる仕様の方がおかしいfinalizeできるべき
だいたいnamespace oresama にX=サンが "bar.h" にて void oresama:foo()を定義して、
C++の標準ライブラリ仕様しか見ていないY=サンが "baz.h" にて同じシグネチャで異なる実装の
void oresama:foo() が実装されてしまう危険性が避けられない
のだから第三者によるnamespace内への後付けは本来言われるまでも無く禁止されるべき事項、
同一シグネチャで異なる実装があったらリンク時にエラーになる、と気体することは場合に掘っては全くできない
http://0xcc.net/blog/archives/000060.html
ちなVS2010だともっと簡単に(スタティックリンクでも)起こせるorz 訂正orz
誤1: C++の標準ライブラリ仕様しか見ていないY=サン
正1: oresamaのオリジナルの仕様書しか見ていないY=サン
誤2: 場合に掘っては全く
正2: 場合によっては全く >>868
話がズレている
前方宣言は規格で合法だよ
(ただし名前空間std内を除く)
鼻から悪魔は出ない...と思う >>872
前方宣言自体はいいよ。
そのライブラリ内でどう定義されているかわかっていて**妥当な前方宣言を出来るなら**。
将来のライブラリの更新があっても妥当でありつづける (または妥当でなくなったときに追従する) なら。
いちいちライブラリが保証していない内部仕様を調査して妥当かどうか確かめなきゃならない、どんな干渉が起きるかわからない
ってのは (ライブラリの仕様としては) 未定義じゃろ。 >>854
タブスタって何が?
stdに勝手に追加やってみた?
コンパイル通るぞ
文法的にどうのということと
できることとやっていいことは違うということを
区別しているか? >>846
C言語はboard[x][y]のy側が連続に配置されるから for(x = ...){ for(y = ...){ ... } } の順にネストした方が効率的になる可能性が高いので俺なら
for (x = 0; x < XMAX; x++){
for (y = 0; y < YMAX; y++){
board[x][y] = 0;
}
num[x] = 0;
}
って書くと思う >>873
前方宣言ってヘッダを見てやるから
逆に妥当でない前方宣言ってどんな場合のことを書いているのですか?
内部仕様を調査する必要もないと思うのですが? oresama 名前空間に前方宣言が追加されると未定義動作になるような例って実際作れる?
std についてはコンパイラマジックでも何でもありだが 未定義動作は未定義だよ
意図通り動いても、
デバッグするのに便利な例外が投げられても、
まともに動いてるように見えてメモリ壊してても、
コンパイルエラーになっても問題ない
コンパイラと実行環境は求められる動作が決まってないから 変な宣言が追加されるとSFINAEが狂うパターンとかあるかも。 >>877
できることとやっていいことは違うということを区別してるかとあんたに聞いているんだ
そこに他人の発言を持ち出す余地はない
答えに窮しているんなら駄レスしねえで黙ってろ >>820
思ったんだけどさ前方宣言は`declarations'に入ってないってことはないかな?
以下が原文なんだけども
>Unless otherwise specified, the behavior of a C++ program is undefined
>if it adds declarations or definitions to namespace std or to a
>namespace within namespace std.
文からは入ってるとも入ってないとも俺には判断がつかない
確かな見解がある人はいるかな? >>884
答えに窮しているんなら駄レスしねえで黙ってろ
てめーの言葉で語れないフリーライダーが
生産性のないやつはプログラマのゴミの中のゴミだ >>884 >859の言う「ダブルスタンダード」は>862-864で否定されて終わってるだろ。 ヘッダファイルそのものを改造することだってできる
ISO/IEC14882のヘッダファイルだけ改造しちゃいけなくて
それ以外のヘッダファイルは改造していいことにしたいのかよ
ダブスタだからって? バカか 標準のヘッダファイルを書き換えるななんてバカ用の説明が規格票の中に書いてあるかどうか知らんが
そういうレベルの屁理屈ならべてんなボケが >>887
>>865以降も読んでくれ給え
前方宣言で鼻から悪魔が出るケースは名前空間std以外ではない
コンパイルエラーやリンカーエラーで弾ける
名前空間stdでもないと思い始めている
規格の`declarations'は普通の宣言のことで
前方宣言はこれに入らない説に傾いてきた >>890,891
何で標準のヘッダファイルを書き換える話を始めてるの? >>820
>>>818
>原則としては std 名前空間になんらかの宣言や定義を追加したら未定義ということになってる。
>https://timsong-cpp.github.io/cppwp/n4861/namespace.std
>その事例も該当すると思う。
これが正しいかもしれんし違うかもしれん >>893
うるせえ命令すんな
読んで欲しければ読みたくなるようにお前が努力しろカス >>894
一緒だろうがよ
stdの中に働きかけて動作を変えようって話だろ
stdだけそれをするなというのがダブスタなんだろ >>896
俺は優しいからね
>>859
>以下をユーザが自分のソースに書くのは>>820の言うように規格で禁じられている
>namespace std {
> template <class T, std::size_t N>
> struct array;
>}
規格で禁じられていると書いている人間が
「できることとやっていいことは違うということを区別して」いないわけなかろう 作者がするなということをなぜしたいんだよ
脱獄したきゃ勝手にやってろ
誰も止めやしねえよ
バカ一匹どうなろうが誰も知ったこっちゃねえ >>897
>stdの中に働きかけて動作を変えようって話だろ
違います >>899
規格の英文が曖昧だから読み間違えてんじゃないの?
って思い始めてる >>904
定義を書いたらこの問題は起こるね
前方宣言では起こらない 「勝手に」が抜けてたorz
X=サンが*勝手*に追加した "bar.h" にて void oresama:foo()を定義のを知らずに
Y=サンが "baz.h" にて同じシグネチャで異なる実装の void oresama:foo() が実装されてしまう
と言う場合は覿面に意図しない動きになる(ことがある >>905
定義の無い前方宣言とか何のためにするんじゃ…… >>870はリンカーがチェックすればこの問題は起こらないはずなんだけど
意図的にオーバライドできるようになってるとか
何かで読んだ気がする... >>907
ヘッダをできるだけincludeしたくないから
ヘッダをincludeしたくないのは依存ヘッダを減らしたいから
みんなpimplとかで前方宣言してるやろ? >>903
読んでるよ
どのくらいか指定がないからどうにでも言えるw
苦し紛れに何が言いたかったのかな >>910
ではあなたは`declarations'に
前方宣言が含まれるとの見解でよろしいか? >>911
前方宣言て何? JIS X3014の規格票を検索してもヒットしないんだが forward declarationじゃないかな? ない? さあ知らんね
おまえの曖昧さを俺が処理してやる義理はない 技術板で煽りネタが英語力とかくだらんな
英語圏在住のバカと同類だってアピールしたら格好いいんかよw >>915
規格が英語で書かれてるんだから仕方ないじゃないか
>>914
威勢が良い割には逃亡か
根性がねーな 煽っても無駄だよ
義理のないことの特別サービスをさせたいようだが
世の中そう甘くはない
暇人と違って明日も朝から仕事なんだよ
バイバイ >>916
おまいさんは威勢よく俺を煽ってたけども
規格も読んでなかったということだ
根拠としたのは恐らく>>820の書き込みのみ
俺は純真なので痛く傷ついたんだよ
他人の言説を無批判に信じて自らは確かめることなく
人を攻撃することはやめてくれ 前方宣言が宣言でない可能性なんて考えたこともなかったが
たとえば単にポインタと書いてあるときにメンバ関数ポインタを含んでなかったりすることを
思い出せば変な用語になってる可能性は考慮にいれるという姿勢は必要かもしれない。
あらためて検討してみたところ、前方宣言という用語の直接的な定義はないが仕様中で
前方宣言 (forward declaration) と呼ばれているものは宣言に該当するし、
単に宣言の位置が前方である宣言のことを前方宣言と呼んでいると解しても良いと思う。 未定義動作だから宣言禁止してるんじゃない
宣言禁止してるから未定義動作になったんだ >>892
>865の質問は>866,868で答えが出てて、その前の話に影響無いし・・・と読み進めると
>872で「前方宣言は規格で合法」とかいう当たり前に見える意味不明な話につづいており・・・
どうも>859以降の「合法」が↓のようなよくある解釈とは違うようであることに気付いた。
https://cpprefjp.github.io/implementation-compliance.html
> 合法 (legal)・違法 (illegal): これらの語はプログラムに対しても慣用されるが、具体的な意味は明確でない。 プログラムの正しさには複数の水準があるためである。 適格、またはすべての規則を満たす、または未定義の動作を含まないなどが考えられる。
明確な言葉で言い換えられるまで下手に考えても不毛そう。
「前方宣言は」というのも「ユーザー側コードに~な前方宣言を加えて利用していた場合にライブラリ更新があっても~」
とかいう意味になりそうだけど端折りすぎて意味不明になってる。
「鼻から悪魔」は未定義動作と同じ意味のつもりで使ってそうだけどコンパイルエラーやリンクエラーは除くようでもあり
これも未定義動作とは違う何か。
さっきキレちらかしてた人もこんな感じで我慢できなくなったんだろう。
明確な用語を使うように気を付けて主張を整理しないと、君とまともに会話してくれる人居なくなると思うよ。 「天才のぼくちんの完璧なレスを理解できない無能なお前らが悪い!」って暴れ出すいつもの奴だからもう放っとけよ >>921
鼻から悪魔はコンパイルエラーやリンカーエラーは当然含まない
何人か知らないようだけどもひょっとして自演してるの? >>921
したがって>>865の答えは出ていない
名前空間stdは>>820のdeclarationsに
前方宣言が入るとは限らないので
答えにはならない
それと俺は天才くんとは別人
横からちゃちゃ入れてる人だよ 「いつもの奴」が一人ということも無いからな。悲しいことに。
コテハン付けてくれない? >>837
本題と関係ないけどこれって CTAD 関連含めて挙動完全に大丈夫なんか?少なくとも C++17 ではダメだが 俺は天才なんて呼ばれたことはないが
天才と呼ばれた人だこのスレで呼ばれたw >>865の結論て>>866で終わってると思うんだけど
前方宣言がdeclarationじゃないとか曲解だろ
たまたま先に同じ型で宣言するという技法がテクニックとして成立するだけ 前方宣言が確かに>>820の`declarations'に含まれる根拠があれば示して下さい
前方宣言で鼻から悪魔が出ることは
懸案事項の名前空間stdの場合は保留として他にないと思う
>>837はコンパイルエラーで弾かれるので鼻から悪魔は出ない
あれば教えて下さい まずあなたがどっちもdeclarationなのにただのテクニックである前方宣言が含まれない理由を示すべきだろう >>943
俺は入るとも入らないとも根拠がないので保留だよ
どちらかの根拠があれば解決だね >>925
コンパイルエラーやリンクエラーも未定義動作で起こりうる事の一つなんだけど
どういう理屈で鼻から悪魔から除外されるの? 違わないよ
何でも起こりうるのが未定義動作だ
お前はコンパイルエラーの方が鼻悪魔出現よりも非現実度が高いと思ってるの? >>945
コンパイルエラーやリンクエラー -> 動作しない
未定義動作 -> 動作する 現実的な話としては、未定義動作静的解析で見つけ出してillーformed扱いしてコンパイル拒否するコンパイラがあったとして、それは規格違反ではない
当たり前だろ、だって未定義なんだから >>944
まず前方宣言がdeclarationという仕様のそとにある可能性を示してくれないと
前方宣言ってdeclarationの言語仕様外の動作してるの? >>948
未定義動作の「動作」(undefined behaviourのbehaviour)は実行時動作だけ意味してるわけじゃない >>950
俺も昨日から規格をあたってるけど見つからんのだよ
Cの規格を見れば良いのかな? >>951
通らない部分は未定義動作のまま残して良いわけだけど
コンパイルが通らないとなると問題だ >>954
何が問題なの?何だろうと問題にしないのが未定義という事だぞ
それ以上言うなら「未定義といえどもコンパイルとリンクは必ず通らなければならない」って規格書に書いてある場所提示してね ソースがWikipediaで申し訳ないが
未定義動作とはコンパイルやリンクを通るものを言う
https://ja.wikipedia.org/wiki/%E6%9C%AA%E5%AE%9A%E7%BE%A9%E5%8B%95%E4%BD%9C
名前空間stdにビルドできるコードを追加しても
動作が意図通りになるか分からんよ
動作は未定義だよってのが>>820の指摘だよ 未定義じゃなくても「必ず通らなきゃならない」なんて記述はないと思うけど >>956 ちがうんだよなぁ。
> CやC++の場合、コンパイラはコンパイル時に未定義動作のチェックを行うことができる
よりC++規格に即した>921のリンク先も見てね。 >>952
普通にdeclaration and definitionの項でも読んでれば良いんじゃないの
前方宣言特有の動作があるのにここにないなら別である可能性も考えて良い >>956
ゴミ持って来んな
しかもそのゴミにもコンパイル前にチェックしてもいい(しなくてもいい)って書いてあるやんけ
>>957
コンパイル出来なかったら問題だとかいう寝言言い出したのはお前の方だろうが >>956
仕様上の定義では未定義の挙動は翻訳中にも生じる。
> https://timsong-cpp.github.io/cppwp/n4861/defns.undefined
> during translation or program execution >>962
ホントだねw
Wikipediaにあるようにコンパイルもリンクも通って
実行はできるときに使うことが多いと思ってたけども >>956
未定義動作はc++標準の規定外というだけで、エラーになるかどうかは全く関係無い。エラーにしてもエラーにしなくてもc++標準には違反しない。
www.open-std.org/jtc1/sc22/wg21/docs/standards
N4849.
3.28 未定義の動作
この文書が要求していない動作
[項目への注記 1: 未定義の動作は,この文書が動作の明示的な定義を省略したとき,又はプログラムが誤った構成又は誤ったデータを使用したときに予想されるかもしれない。
未定義動作は,この文書が動作の明示的な定義を省略した場合又はプログラムが誤った構成若しくは誤ったデータを使用した場合に想定される。許容される未定義の動作
予測できない結果をもたらす状況の完全な無視から、翻訳中またはプログラム実行中に特徴的な文書化された方法で動作することまで、許容される未定義動作の範囲があります。
環境に応じて文書化された方法でプログラムの実行を行う(診断メッセージの発行の有無は問わない)。
また、翻訳や実行を終了する(診断メッセージを発行する)こともあります。)
多くの誤ったプログラム構成は、未定義の動作を発生させるものではなく、診断が必要なものである。
定数式の評価は、本書第 4 条から第 15 条で明示的に未定義と指定された動作にはならない。
から第15項(7.7)までに明示的に未定義と指定された動作を示すことはない。- エンディングノート] >>964
有難う
用語は注意して使わないとね
>>865の質問を正確にすると
前方宣言を自分のソースに追加すると
ビルドはできるが動作が未定義となる設計は本当にあるの?
(もちろんstdは懸案事項なので保留するとしてそれ以外でね) stdだと未定義とするって仕様なのにstd保留してどうするんだ
未定義にならずにコンパイラが仕様通りの解釈して動作するだけだろ 言語的には仕様通りの解釈をするがそれがそのライブラリにとって想定外であるような、
つまり本来の動作と異なる結果を引きおこすような形での前方宣言がありうるかという意味だろ。 それっぽい例を作れた!
https://wandbox.org/permlink/6utNhLox1WhOaBV8
とはいっても適切な前方宣言になっていないから起こっていることではあるので、
「ヘッダを見て間違いなく前方宣言としては適切になるように書いたけど挙動には影響ある」という例にはなってない。 >>966
話が通じんなw
その仕様を俺は疑っているから保留
正確に言うとdeclarationsに前方宣言は含まないかもしれんと思っている じゃ小学生の自由研究の時期が終わったら呼んでください ボクちゃんの痛い自由研究
「stdネームスペースに落書き」 じゃあ、ISOで未定義の時は、コンパイラの仕様を調べて使えば良いのでは? 移植とかでコンパイラ変わったら意図しない実行するとか平気ならな >>968
確かに前方宣言で挙動変わるね
しかしこのトリッキーな例をもって
前方宣言を自分の管理外の名前空間(std以外でも)に
追加するのが危険と言って良いものかは正直悩む >>972,973
俺は絶対にstdはいじらないね 自作クラスでendlなどのマニピュレータをオーバーライドするにはstd名前空間に入れるしかないじゃない? つうかstdが「標準である」と言う設計上前方宣言を禁止したから仕様上未定義動作となっただけの話で
危険だから前方宣言すべきじゃないって話じゃないと思うよ
結果的にコンパイラ側がそれを逆手にとって最適化とか推し進めた形になったとしてもね
前方宣言許さない仕様のライブラリって言うのは危険だからじゃなく
勝手に拡張すること許さないと決めたライブラリであるというだけの話で >>977
ストリームはホント腹立つよな。
ぶっ飛ばしたくなってきた。
30年くらい怒りが収まらん。 ostream と istream の別の建てつけなので、ファイルポインタもこの二つのクラスで別なんだろうと思っていたら、土壇場で、実はファイルポインタは共有していましたぁ
とか勘弁してほしいと痛切におもいましたねえ >>978
そういうのは「改造c++」とでも言うべきもので、個々の具体的な実装を挙げて話すべき話題。
具体的な実装の無い「改造c++」なんて「オレ言語」でしかないから、話題にしても相手にするヤツは居ないよ。興味無い。 >>981
まさかプロトタイプが30年後も使い続けてるとは思わなかったんだよ >>974
「わからない」という状態が最大のリスクだ。 精査して事情を把握してからやる分にはいいよ。
だけど少なくとも私はいちいちライブラリの細かいことなんて調べたくないし、
細部の事情まで読み解ける自信はないから製作者の意図 (仕様として明示されている範囲) を超える
ような使い方をあえてすることはないだろうという話。 要するに割に合わない。
しなくていいことはせずに済ませられたらそのほうがいいだろ。
割に合うと考えている人がいたとしたら
「んなわけねーだろ。 お前が調べるのに労力をかけてないだけ」
と思うから安易にやっちゃうやつはちょっとナメてるように感じる。
そりゃあ他に打てる手がなければ割に合わなくてもやらざるを得ないことだってあるだろうけどさぁ。 本当に余計なお世話だけど、はちみつさんのような実力がある人は
むしろライブラリやコンパイラのソースを読んだ方がいいよ std名前空間への勝手要素追加は未定義動作と書かれているのに
std名前空間内のクラスへのメンバ追加についてはなんで言及が無いのやろうな……
名前空間もクラスもPGの責任分担範囲の区切りみたいなもんで、
第三者に後から勝手に弄られたら設計したPGが困るのは同じだと思うのだけど、 自分はできるPGですと自己申告する>>992……
その自身がどこから来るのかは誰も知らない…… そんなこと思ってない
いままで見てきた汚いソース書いている連中の総意点を述べているだけのこと つまりstd名前空間のソースは汚いから
予防のためにstd名前空間への勝手要素追加は未定義動作とするのがstdを設計したPGの立場では当然だと、 バカなの?
なんのための名前空間なのかよく考えろよ
設計を区分するためだろ
そこにお前みたいなワケワケな奴が落書きしたらめちゃくちゃになるだろ stackoverflow 辺りで
皆さんの御意見を聞いて来いよw 後のこと考えて設計するよりも先に手が動くような人じゃないとプログラミングは上達しないよ >>998
もうお前の尻拭いするの嫌だよ
たのむから手動かす前に3分くらい考えてくれ 昔はさ、ウォーターフォールといって
完璧な設計ができるまでコードに手を出すな
設計が決まったら黙ってそれに従うコードを書け
なんてのがあったけど
前例のないものの完璧な設計なんてほいっとできるのか
現場からのフィードバックを無視なんてできるのか
って反省から今時の方法論ができているわけで
ただし、それを悪用するだけの寄生虫を擁護はしない このスレッドは1000を超えました。
新しいスレッドを立ててください。
life time: 60日 3時間 50分 35秒 5ちゃんねるの運営はプレミアム会員の皆さまに支えられています。
運営にご協力お願いいたします。
───────────────────
《プレミアム会員の主な特典》
★ 5ちゃんねる専用ブラウザからの広告除去
★ 5ちゃんねるの過去ログを取得
★ 書き込み規制の緩和
───────────────────
会員登録には個人情報は一切必要ありません。
月300円から匿名でご購入いただけます。
▼ プレミアム会員登録はこちら ▼
https://premium.5ch.net/
▼ 浪人ログインはこちら ▼
https://login.5ch.net/login.php レス数が1000を超えています。これ以上書き込みはできません。