C++相談室 part162

■ このスレッドは過去ログ倉庫に格納されています
1sage (ワッチョイ fbf0-ofdD)
垢版 |
2022/10/31(月) 14:29:35.57ID:J5sgTSch0
!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
2022/10/31(月) 17:11:42.28ID:FSs0hrWX0
保守です
2022/11/01(火) 07:31:00.75ID:8mAHYLmxd
寿限無寿限無五劫の擦り切れ海砂利水魚の水行末雲来末風来末食う寝る処に住む処藪ら柑子の藪柑子パイポパイポ パイポのシューリンガンシューリンガンのグーリンダイグーリンダイのポンポコピーのポンポコナーの長久命の長助
2022/11/01(火) 12:22:19.23ID:LNKvo44sd
今更話すことある?
2022/11/03(木) 09:15:40.37ID:AvIGv7Uk0
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...>&&) {}

うーん、困った
どうしよう。。。
2022/11/03(木) 10:13:40.98ID:GMyBvZ220
requires map_t<MAP>でええやん
2022/11/03(木) 10:30:49.88ID:AvIGv7Uk0
あ、そっか
㌧x

一応、報告
template <template<class...> class MAP, class... ARGS> requires map_t<MAP> //OK
void test(MAP<ARGS...>&&) {}
2022/11/03(木) 18:33:03.71ID:A3AnwOcy0
テンプレートにテンプレート重ねて滅茶苦茶する典型
2022/11/03(木) 20:41:25.83ID:GMyBvZ220
AssociativeContainer要件のコンセプトは標準ライブラリには無いんだな
規格上定義してるrequirementは一通り作っとけばいいのに
2022/11/03(木) 22:05:17.66ID:f0rgVbxY0
>>8
でも文法的コンパイラ的には許されている
100段くらい重ねて大丈夫なんじゃなかろうか
2022/11/03(木) 22:28:39.04ID:b1nVlp4p0
>>10
コンパイラが無限のリソースを使えるわけじゃないから制限があってもいいし、
わかっている制限は文書化するべきということになっている。
https://timsong-cpp.github.io/cppwp/n3337/implimits

言語仕様の側でもどの程度まで処理すべきかという最低限の数値は与えていて
この場合だと
Recursively nested template instantiations [1024].
ってのが当てはまる。
あくまでもガイドラインなのでこれ以下に制限された処理系がないとは言えないんだけど、
1024 が提示されているところで 100 やそこらに制限するような処理系はたぶんあんまりないとは期待できると思う。
2022/11/04(金) 14:22:03.44ID:MccBwaps0
そんなん言い出したら自動変数は合計何バイトまでとか
しょーもないことを規格票に書くハメにならないか?
2022/11/04(金) 14:28:53.41ID:I5Ua2kB10
GCCとClangの -ftemplate-depth-?? の話?
2022/11/04(金) 15:45:10.91ID:nV9i8Ccmd
昔は17だったなその制限
2022/11/04(金) 16:29:55.40ID:MccBwaps0
つーかよ
俺5だけど、あの程度のことで
8みたいなこと言われたのずっこけてる

別に無駄に複雑化はしてないし裏技も使ってない
当たり前の書き方で目的を素直に書いてるだけなのに

一次テンプレートと特殊化でis_系のクエリーを作って
それでコンセプト作って使おうとしただけだぜ?
何があかんの?

テンプレートテンプレート仮引数がわからんだけじゃないのかって邪推しちまいそう
2022/11/04(金) 16:49:46.97ID:nV9i8Ccmd
全然あかんくないと思うよ
8がアホなだけ
2022/11/04(金) 18:04:41.45ID:I5Ua2kB10
話は綺麗に終わってるのに
発展的に関連した話題を振るのならともかく
何で>>8みたいなコメントをいちいち付けるのか俺も理解不能
2022/11/04(金) 18:07:42.31ID:I5Ua2kB10
>>14
そうそう昔はこれを付けないで17超えるとエラーが出てた
-ftemplate-depth-100 くらいで使ってたけど
いまはデフォルトで1024になってるのね
2022/11/04(金) 19:44:51.78ID:lXYNWX4U0
制限はあくまでも「深さ」であって「回数」ではないので上手いこと変形するのも技の内だったんだよな……。
遊びでやるならきつめの制限も楽しいんだけどね。
2022/11/05(土) 15:23:46.47ID:6woT7hPv0
自動的に解釈されるテンプレート引数で
値渡しじゃなく参照渡しと解釈させる方法ってありますかね?
2022/11/05(土) 15:33:58.60ID:95t5abQGd
std::ref
std::cref
2022/11/05(土) 15:40:28.55ID:6woT7hPv0
あるんですねぇ
ありがとうございます
2022/11/07(月) 14:57:30.80ID:8LbwGvMzM
明示的な型変換が可能か調べる方法ってありますか?
暗黙的ならis_convertibleが使えるのですが…

std::is_convertible<std::shared_ptr<void>, bool>::value; // trueになってほしい
2022/11/07(月) 16:58:07.91ID:2UaeFBkad
is_constructibleを使う
2022/11/07(月) 17:32:26.98ID:unROdsfFM
>>23
std::is_constructible<bool, std::shared_ptr<void>>::value

ありがとうございました。
2022/11/07(月) 17:32:50.90ID:unROdsfFM
>>24
ありがとうございました。
27デフォルトの名無しさん (ササクッテロロ Sp79-uppo)
垢版 |
2022/11/09(水) 10:37:27.83ID:uQIa4jnTp
質問です
マネージドとかアンマネージドとかMSの呪いですか?
2022/11/09(水) 11:23:16.37ID:GzNJb2MKM
プログラミング言語 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 );
・・・
}
ここで問題となるのは、以下のどちらの方法で解釈されているかということです。
[続く]
2022/11/09(水) 11:24:30.65ID:GzNJb2MKM
>>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)だと上手く行かない気がします。
[続く]
2022/11/09(水) 11:25:24.81ID:GzNJb2MKM
>>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へと変換される。
2022/11/09(水) 16:50:18.10ID:XEaxVtCg0
大体わかってそうだけど
{…}をinitializer_list<Entry>として解釈しようと試みる→中身の{"David Hyme",123456}とかをEntry型に暗黙変換しようと試みる→全部変換できれば成功
Entryがexplicit Entry(string, int);を持ってると暗黙変換できなくて失敗するようになる
2022/11/10(木) 00:59:56.86ID:8S99EFBAM
>>31
vector<T>クラスのコンストラクタに、initializer_list<T> 以外の引数を
持つものが存在していた場合、どういう優先順位でコンストラクタが選ばれて
いくのでしょうか。
コンパイラは、最初に初期化子の {・・・} の部分のカンマで区切られた中身の
個数を数えてから、その個数によってどのコンストラクタを選ぶかを決めますか?
2022/11/10(木) 01:07:30.02ID:8S99EFBAM
>>32
仮にそうだとすると、コンパイラの内部では、
1. vector<Entty> phone_book の宣言の型である vector<Entty>を把握。
2. = の右側の初期化子の部分の{}の中の個数など大まかな特徴を掴む。
3. 2の特徴に基いて最適なvector<Entry>のコンストラクタを探す。
4. = の右側の部分を3.のコンストラクタに基いて解釈/変換する。
という少なくとも4段階の工程を得ていることになりそうですが、随分と
特殊な解釈の仕方ですね。
通常の式ならば、このように「いったりきたり」はしないものですが。
2022/11/10(木) 07:25:48.25ID:JLZuLXt50
そこは通常のオーバーロード解決と同じだけど何が気に食わないの?
f(int)とf(int,int)があってf(1,2)を解決するときに「先に引数が2個あることをチェックするなんてインチキだ!」って発狂されても
2022/11/10(木) 12:27:18.30ID:Ma0XsUW1M
>>34
しかし、その場合、どの関数を呼び出すかが決定されてから後に、パラメータ(実引数)
の意味解釈は変化せず、実引数の解釈は同じで、必要あらば関数の仮引数へとcastされるだけです。
ところが、今回の初期化子の場合は、実引数の大体の様子が調査された後に、
どのコンストラクタを使うかが決定。コンストラクタが決定された後に、実引数の
意味解釈まで変わります。
2022/11/10(木) 12:30:32.91ID:Ma0XsUW1M
>>35
[補足]
前半の通常の関数の場合、コンパイラの内部で隠れてcastされるという訳ではなく、
必要あらばちゃんとcastに必要な「変換関数」が呼び出されることまで決まって
おり、マシン語レベルで変換関数を呼び出だすcall文が生成され、その中で
変換に必要なマシン語の列が実行されます。
ところが、後半の初期化子の場合、その変換関数が呼び出されない可能性が高い
です。なぜなら、変換ではなく、最初からのコンストとラクタの仮引数の
型に合わせて意味解釈されて、いきなりその型としてコンパイルされるためです。
2022/11/10(木) 12:33:49.93ID:Ma0XsUW1M
>>36
[補足2]
気に食わないのではなく、不規則変化というか、C++の一般法則とは異なる
法則が流れているようで、難しいな、と思ったまでです。
38デフォルトの名無しさん (エムゾネ FFb2-DoDL)
垢版 |
2022/11/10(木) 12:36:36.70ID:43j6CzLZF
これvector<Entry>に
std::array<Entry,3>とか
std::tuple<std::pair<const char*, int>, std::pair<const char*, int>, std::pair<const char*, int>>
とか受け取るコンストラクタが追加されてたらまた話変わったりするよね

一応全部合法的に受け取れるはずだから、
コンパイラはどう解決するべきかってのを >>28 は聞きたいんだと思う
39デフォルトの名無しさん (スッップ Sdb2-DoDL)
垢版 |
2022/11/10(木) 12:40:22.21ID:IDnNuz1Ud
なんか書き込んでからどっちもコンパイル通らないような気がしてきた
忘れてくれ
2022/11/10(木) 13:04:32.16ID:kKaeKygLd
>>38
その場合は曖昧だって怒られるだけ
2022/11/10(木) 13:24:31.23ID:WlLaCVUwd
初期化子をコンストラクタのオーバーロード候補(静的に決まる)にそれぞれ適合させてみて、どれもダメならエラー、複数当てはまるなら優先度に従って1個に絞れたらそれを選択、曖昧ならエラー

初期化子や優先度の複雑怪奇なルール詳細の事ならともかく、この大枠の話の何がそんなに原則外れで難しいと思ってるのか正直さっぱりわからない
42デフォルトの名無しさん (オイコラミネオ MM91-wgF3)
垢版 |
2022/11/10(木) 13:24:55.21ID:Ma0XsUW1M
>>37
[補足4]
fという名前だが仮引数の型が異なる持つ関数f()が複数ある場合は、
f(a);
と書いた場合、aの部分が完全に意味解釈されて、aの型が完全に決まってから、
どのf()が呼び出されるかを選択。
選択されたf()の仮引数の型Tと実引数aの型を比較して、異なっていれば、
aの型をTに変換する変換関数を呼び出し、変換後の値を関数f()の引数として
関数f()を呼び出す。

ところが、初期化子の場合、
T v = b;
と書くと、bの型を軽く調査するが、完全には b が意味解釈される前にどの T のコンストラクタ
を呼び出すべきかの調査が始まる。その時点では、bの型は完全には決まってない。
2022/11/10(木) 13:28:29.70ID:Ma0XsUW1M
>>41
>初期化子をコンストラクタのオーバーロード候補(静的に決まる)にそれぞれ適合させてみて、どれもダメならエラー、複数当てはまるなら優先度に従って1個に絞れたらそれを選択、曖昧ならエラー
Tのどのコンストラクタを使うかが決まるまでは、初期化子の中身の型が決まりません。
なので、総当り的にチェックすることが不可能だということになります。
(原因と結果が逆なので)。
なお、Tのどのコンストラクタを使うかを決める際に、初期化子のある程度の様子は
必要になりますのでややこしくなっています。
2022/11/10(木) 14:13:26.85ID:99QPf7Vaa
>>36
関数だって定数(もしくは定数になる式)渡したら変換関数なんか呼ばずに変換後の値を渡すようにコンパイルするだろ
2022/11/10(木) 15:49:32.45ID:kY0Aveh/d
>>43
型が決まらないって何のこっちゃ
君の例だと"David Hyme"はconst char*だし123456はintだし、
{"David Hyme",123456}はEntry(に集成体初期化で暗黙変換可能)で、他の要素も全部そうだから初期化子全体はinitializer_list<Entry>(に暗黙変換可能)なのでvector(initializer_list<Entry>)が適合可能、って全部静的に決まる話だぞ(正確にはもっとややこしいけど)
どこに動的型が出てくると思った?
2022/11/10(木) 21:41:21.36ID:lrIHTbD+0
自分の認識と実際の動作の間に食い違いがあることを質問したのに
その認識の間違いを指摘されても認めたくない人って厄介だね。
47デフォルトの名無しさん (ササクッテロロ Sp79-uppo)
垢版 |
2022/11/10(木) 21:44:22.55ID:xu9+brpFp
プログラムは書いた通りにしか動かない

って奴だな
2022/11/10(木) 21:59:32.65ID:ycxEOHBI0
自分の認識の通りのコンパイラを作るってんならご自由にだが
そうでない以上認識を改める他なかろう
2022/11/10(木) 22:00:55.26ID:8bOle1Do0
依存性逆転の原則または依存関係逆転の原則
2022/11/10(木) 22:21:23.00ID:XJxScCwYM
>>45
動的な型のことは一切言及していません。
私のIQは170以上あるので、普通のプログラマには質問の意味が理解できてない可能性があります。
2022/11/10(木) 22:22:55.08ID:XJxScCwYM
2ch/5chでレベルが高い質問をすると、バッシングを受ける傾向が有ります。
52デフォルトの名無しさん (ササクッテロロ Sp79-uppo)
垢版 |
2022/11/10(木) 22:23:43.35ID:xu9+brpFp
頭が良い人なら、馬鹿にも分かる説明も難なくこなすんだがなぁ
自称してるだけの馬鹿なら意味不明な話を相手の理解力のせいにするんだよなぁ
■ このスレッドは過去ログ倉庫に格納されています
5ちゃんねるの広告が気に入らない場合は、こちらをクリックしてください。

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