C++に関する質問やら話題やらはこちらへどうぞ。
ただし質問の前にはFAQに一通り目を通してください。
IDE (VC++など)などの使い方の質問はその開発環境のスレにお願いします。
前スレ
C++相談室 part149
https://mevius.5ch.net/test/read.cgi/tech/1581974381/
このスレもよろしくね。
【初心者歓迎】C/C++室 Ver.105【環境依存OK】
http://mevius.5ch.net/test/read.cgi/tech/1556142878/
■長いソースを貼るときはここへ。■
http://codepad.org/
https://ideone.com/
[C++ FAQ]
https://isocpp.org/wiki/faq/
http://www.bohyoh.com/CandCPP/FAQ/ (日本語)
テンプレここまで
C++相談室 part150
■ このスレッドは過去ログ倉庫に格納されています
2020/03/24(火) 00:04:33.93ID:YFRNwZnv
744デフォルトの名無しさん
2020/05/07(木) 10:45:35.17ID:Uptrp4d8 >>741
- std::atomicの使いどころを理解してない
- "OS"の同期プリミティブを使えと主張 (なぜOSと限定?)
この二つの条件を満たす別人が現れる確率は結構低いと思ったんでね
非礼の詫びとしてatomicの使いどころ知りたかったら教えてやるけどどう?
- std::atomicの使いどころを理解してない
- "OS"の同期プリミティブを使えと主張 (なぜOSと限定?)
この二つの条件を満たす別人が現れる確率は結構低いと思ったんでね
非礼の詫びとしてatomicの使いどころ知りたかったら教えてやるけどどう?
745デフォルトの名無しさん
2020/05/07(木) 10:50:13.38ID:Uptrp4d8746843
2020/05/07(木) 11:13:09.18ID:lQhGrp4h747デフォルトの名無しさん
2020/05/07(木) 11:20:48.41ID:Xvq6sZ7Q std::atomic<double>はoperator+=ないね
748デフォルトの名無しさん
2020/05/07(木) 12:09:28.57ID:0pZrsm5h749デフォルトの名無しさん
2020/05/07(木) 12:11:04.76ID:0pZrsm5h750843
2020/05/07(木) 12:17:56.15ID:FtlEpNqJ751デフォルトの名無しさん
2020/05/07(木) 12:53:58.73ID:N+2vUAWE752デフォルトの名無しさん
2020/05/07(木) 17:00:45.03ID:jqbAFx8V C++に限ったことじゃないかもしれないんですけど質問させてください
typedefで型に別名つけることについてです。今いじってるコードでたとえばvector<animal>にanimalsって型名をつけるようなのが山のようにあるんです
これすごくわかりにくいなと思います。例えばvector<animals>で宣言されてればその変数にどんな操作ができるのか一発ですが突然animalsで宣言されても何ができる型なのか初見では分かりません
別名をつけることがメリットになることってあるんでしょうか
typedefで型に別名つけることについてです。今いじってるコードでたとえばvector<animal>にanimalsって型名をつけるようなのが山のようにあるんです
これすごくわかりにくいなと思います。例えばvector<animals>で宣言されてればその変数にどんな操作ができるのか一発ですが突然animalsで宣言されても何ができる型なのか初見では分かりません
別名をつけることがメリットになることってあるんでしょうか
753デフォルトの名無しさん
2020/05/07(木) 17:14:48.12ID:8jv+kISL メリットは君が言ってる通り特定の言語に限った話では特定の回答は出て来ないし
言語を取り巻く環境(エディタや統合環境や諸々)でも答えは変わってくる
言語を取り巻く環境(エディタや統合環境や諸々)でも答えは変わってくる
>>752
using animals = std::vector<animal>;
わたしも、こういう typedef はしない方ですね、リッチなエディターを使っていないせいかもしれません
書いた人は別名を細かく付けた方がいいと考えているようですが、こういうのは記述の粒度の問題かもしれませんね
using animals = std::vector<animal>;
わたしも、こういう typedef はしない方ですね、リッチなエディターを使っていないせいかもしれません
書いた人は別名を細かく付けた方がいいと考えているようですが、こういうのは記述の粒度の問題かもしれませんね
755デフォルトの名無しさん
2020/05/07(木) 18:08:47.80ID:cLsDnrKi >>752
例えば後からvectorじゃなくてlistにしたいなーと思ったときに修正箇所が一箇所で済む
例えば後からvectorじゃなくてlistにしたいなーと思ったときに修正箇所が一箇所で済む
756デフォルトの名無しさん
2020/05/07(木) 18:14:03.65ID:V086WOzl テンプレートで使うからでは。
757デフォルトの名無しさん
2020/05/07(木) 18:29:01.78ID:0pZrsm5h >>752
書くのが簡単になり、見るのも分かり易くなることがある。
また、animal_s とちゃんと最後に複数形を現す「_s」を付けるという
自分なりの命名規則を付けておけば、vector<animal> のことである
こともすぐに分かる。
書くのが簡単になり、見るのも分かり易くなることがある。
また、animal_s とちゃんと最後に複数形を現す「_s」を付けるという
自分なりの命名規則を付けておけば、vector<animal> のことである
こともすぐに分かる。
758デフォルトの名無しさん
2020/05/07(木) 18:31:07.04ID:0pZrsm5h >>757
なお、型名は小文字ではなく、Animal か、CAnimal、TAnimal のようにするのが慣例。
vector<Animal> の場合、AnimalVector とすると、書くのも理解するのも楽になる。
templateのままをコード中に大量に書くとわずかな書き間違いで変な動作になりかねない。
なお、型名は小文字ではなく、Animal か、CAnimal、TAnimal のようにするのが慣例。
vector<Animal> の場合、AnimalVector とすると、書くのも理解するのも楽になる。
templateのままをコード中に大量に書くとわずかな書き間違いで変な動作になりかねない。
759デフォルトの名無しさん
2020/05/07(木) 18:36:04.65ID:0pZrsm5h >>758
templateは、C++の中でも最も複雑で、書き間違えたときのエラーが理解しにくい
とされる部分。
だから、vector<Animal>とコードのそこかしこに書きまくるのはお勧めしない。
それと、<や> は、キーボードの配置からして打ち込みにくいという事情もある。
指が届きにくい場所にあるというか。
また、vector<Animal
と> を書き損じたような場合、>を探してコンパイラが変な場所でエラーを出して
しまい、どこでエラーが始まったか探し出すのに苦労するようなこともある。
だから、このような「組み立てられた型」は、毎度毎度そのまま使うと痛い目に
遭う可能性があるので、animals と typedef した人は賢い。
templateは、C++の中でも最も複雑で、書き間違えたときのエラーが理解しにくい
とされる部分。
だから、vector<Animal>とコードのそこかしこに書きまくるのはお勧めしない。
それと、<や> は、キーボードの配置からして打ち込みにくいという事情もある。
指が届きにくい場所にあるというか。
また、vector<Animal
と> を書き損じたような場合、>を探してコンパイラが変な場所でエラーを出して
しまい、どこでエラーが始まったか探し出すのに苦労するようなこともある。
だから、このような「組み立てられた型」は、毎度毎度そのまま使うと痛い目に
遭う可能性があるので、animals と typedef した人は賢い。
760デフォルトの名無しさん
2020/05/07(木) 18:37:12.86ID:N8w6+mz8 >>744
レスするなと言ってるのにほんと人の話を聞いてないな。だから別人だって言ってるだろう。
std::atomicの使いどころってstd::atomicの話題に一度もレスしてないし、std::atomicの話を振られてもいない。
しかもOS限定とか妄想そのもの。
> OSの同期か適当な同期ライブラリ使え。悩む余地なし。
と最初に言ってる。逆にキミのその発言で、キミは今まで禄にコードを書いたことのない糞ガキの学生ということがよくわかったよ。
仮にOS提供の同期機構かstd::atomicかという選択であっても1nmもstd::atomicの選択余地はない。0%だ。
枯れてないライブラリは論外。同期バグはOr****やIntelでもやらかすし、枯れてるほうを使う。
何十年もカーネル開発者が注力し、コキ使われてきた実績のある同期コードを選ぶのがまともな社会人。
キミのような無責任な子供やテストしないOSSな人じゃないからね。OS提供がなくても同じ。
組み込み系ならチップメーカーが提供する同期ライブラリを使う。
レスするなと言ってるのにほんと人の話を聞いてないな。だから別人だって言ってるだろう。
std::atomicの使いどころってstd::atomicの話題に一度もレスしてないし、std::atomicの話を振られてもいない。
しかもOS限定とか妄想そのもの。
> OSの同期か適当な同期ライブラリ使え。悩む余地なし。
と最初に言ってる。逆にキミのその発言で、キミは今まで禄にコードを書いたことのない糞ガキの学生ということがよくわかったよ。
仮にOS提供の同期機構かstd::atomicかという選択であっても1nmもstd::atomicの選択余地はない。0%だ。
枯れてないライブラリは論外。同期バグはOr****やIntelでもやらかすし、枯れてるほうを使う。
何十年もカーネル開発者が注力し、コキ使われてきた実績のある同期コードを選ぶのがまともな社会人。
キミのような無責任な子供やテストしないOSSな人じゃないからね。OS提供がなくても同じ。
組み込み系ならチップメーカーが提供する同期ライブラリを使う。
761デフォルトの名無しさん
2020/05/07(木) 18:39:12.04ID:0pZrsm5h 命名規則は、animals よりも、
vector<animal> の時には、AnimalVector
list<animal>の時は、AnimalList
とするのがお勧め。
最後の s だけだと、見落とす可能性があることと、集合体であることだけは
分かっても、それが、どんな種類の集合体かまでは分からないため。
vector<animal> の時には、AnimalVector
list<animal>の時は、AnimalList
とするのがお勧め。
最後の s だけだと、見落とす可能性があることと、集合体であることだけは
分かっても、それが、どんな種類の集合体かまでは分からないため。
762デフォルトの名無しさん
2020/05/07(木) 18:42:48.91ID:0pZrsm5h もうひとつ、vector<animal> より、AnimalVector とした方がいい理由は、
正規表現検索する場合のため。
正規表現だと、< や > は何らかの meta 表現的な意味を持っている場合があるかも
知れないので、型名は単純な alphabet 列の方が何かと便利。
正規表現検索する場合のため。
正規表現だと、< や > は何らかの meta 表現的な意味を持っている場合があるかも
知れないので、型名は単純な alphabet 列の方が何かと便利。
763デフォルトの名無しさん
2020/05/07(木) 19:54:24.58ID:RMklkh4T 今どきシステムハンガリアンもどきなんてやだよぅ
764デフォルトの名無しさん
2020/05/07(木) 20:03:35.58ID:wkYaXeHy vectorからlistに変えられなくなる
>>761
vector から list に変えるときに、名前もいちいち変えないといけないのだったら、その命名ルールは今いちですね…
vector から list に変えるときに、名前もいちいち変えないといけないのだったら、その命名ルールは今いちですね…
766デフォルトの名無しさん
2020/05/07(木) 20:56:23.62ID:V9Hy6a5I Animalsの話題はわたくしがC++最大の謎と呼ぶvector継承不可問題だ
Javaだと「class Animal extends ArrayList<Animal>{」とできる
でもC++だとvectorそのものの継承はデストラクタの関係で認められていない
つまりクラスを作るかtypedefするか、C++には2通りの解決方法が存在する
Javaだと「class Animal extends ArrayList<Animal>{」とできる
でもC++だとvectorそのものの継承はデストラクタの関係で認められていない
つまりクラスを作るかtypedefするか、C++には2通りの解決方法が存在する
767デフォルトの名無しさん
2020/05/07(木) 21:04:23.79ID:+JcfXk10 自分作りゃいいだろ
コンテナくらい
コンテナくらい
768デフォルトの名無しさん
2020/05/07(木) 21:04:44.42ID:Gk4UMZDB 別にvector継承してもいいんだよ
protectedかprivate継承する分には何の問題もない
役には立たないけど
protectedかprivate継承する分には何の問題もない
役には立たないけど
769デフォルトの名無しさん
2020/05/07(木) 21:07:22.98ID:qT/QDoOR この程度でs付け忘れるとか不注意にもほどがある
770デフォルトの名無しさん
2020/05/07(木) 21:10:02.94ID:QyPqnZke いや、vectorは今となっては継承すべきでないってこともないだろ
771デフォルトの名無しさん
2020/05/07(木) 21:21:54.60ID:hoUWiCnf vector<>のデストラクタが仮想でないのは仕様の欠陥ですか?
772はちみつ餃子 ◆8X2XSCHEME
2020/05/07(木) 21:30:23.98ID:8B1BhNza 注意深さに自信があるならデストラクタが virtual でないクラスを public 継承しても
それ自体は言語仕様には反しないけど、人間は間違うのでな……。
>>768
private 継承した上で外部から呼び出しを許すメンバ関数は using すればいい。
役に立たないということはないと思う。
それ自体は言語仕様には反しないけど、人間は間違うのでな……。
>>768
private 継承した上で外部から呼び出しを許すメンバ関数は using すればいい。
役に立たないということはないと思う。
773デフォルトの名無しさん
2020/05/08(金) 01:16:40.31ID:Fn7VYFHg 基本的なことだと思うけどよく
よくあるイベントループってどうやったらシンプルかつMT安全かつ効率的に実装できる?
次のような条件で
- qeueuが空ならwaitする
- qeueuにイベントが追加されたら直ちにおきてdispatchする
- dispatchに長い時間かかることもありえる
- add_eventは可能な限り短い処理で完了する。
- stopがよばれたらloopから直ちにぬける。dispatch中の場合は終わってから抜ける。
次に雰囲気コード書きます。
よくあるイベントループってどうやったらシンプルかつMT安全かつ効率的に実装できる?
次のような条件で
- qeueuが空ならwaitする
- qeueuにイベントが追加されたら直ちにおきてdispatchする
- dispatchに長い時間かかることもありえる
- add_eventは可能な限り短い処理で完了する。
- stopがよばれたらloopから直ちにぬける。dispatch中の場合は終わってから抜ける。
次に雰囲気コード書きます。
774デフォルトの名無しさん
2020/05/08(金) 01:21:33.28ID:Fn7VYFHg loop()がこれではいかんのはわかってるけど、どうすれば簡潔に書けるのかわからん
他にもあやしいところがある気がする
bool running = true;
std::deque<int> unsafe_queue;
std::mutex mtx;
std::condition_variable cond;
using unique_lock = std::unique_lock<std::mutex>;
void stop() { running = false; }
void add_event(int i)
{
unique_lock _(mtx);
unsafe_queue.push_back(i);
cond.notify_one();
}
void dispatch(int) { /*do something*/ }
void loop()
{
unique_lock lock(mtx);
while (running) {
cond.wait(lock, [] { return !unsafe_queue.empty(); });
auto ev = unsafe_queue.front();
unsafe_queue.pop_front();
dispatch(ev);
}
}
他にもあやしいところがある気がする
bool running = true;
std::deque<int> unsafe_queue;
std::mutex mtx;
std::condition_variable cond;
using unique_lock = std::unique_lock<std::mutex>;
void stop() { running = false; }
void add_event(int i)
{
unique_lock _(mtx);
unsafe_queue.push_back(i);
cond.notify_one();
}
void dispatch(int) { /*do something*/ }
void loop()
{
unique_lock lock(mtx);
while (running) {
cond.wait(lock, [] { return !unsafe_queue.empty(); });
auto ev = unsafe_queue.front();
unsafe_queue.pop_front();
dispatch(ev);
}
}
775デフォルトの名無しさん
2020/05/08(金) 03:21:51.97ID:7git1+gm まずconcurrent_queueを持ってくるなり作るなりして用意した方がいいよ
イベントループにロックやイベント混ぜて書くとわけわからなくなる
イベントループにロックやイベント混ぜて書くとわけわからなくなる
776デフォルトの名無しさん
2020/05/08(金) 03:34:19.21ID:7git1+gm イベントって同期イベントね
777デフォルトの名無しさん
2020/05/08(金) 03:38:35.90ID:FOXu+lyu concurrent_queueは必要ないと言うかこの用途だと無駄な処理増えるだけじゃね
779デフォルトの名無しさん
2020/05/08(金) 06:51:21.78ID:M/JmLjh0 >>774
それ、イベント発行しないと止まらなくね?
それ、イベント発行しないと止まらなくね?
780デフォルトの名無しさん
2020/05/08(金) 11:45:01.04ID:Fn7VYFHg781デフォルトの名無しさん
2020/05/08(金) 12:06:11.41ID:Fn7VYFHg782デフォルトの名無しさん
2020/05/08(金) 12:18:21.10ID:Fn7VYFHg >>778
BlockingCollectionってどこにあります?
ぐぐったらC#のクラスは見つかりましたが
上に書いた通り、stop時の処理がまわりくどくなりそうなのを気にしてます
実行時のロジックがシンプルなやり方を追求したいです
BlockingCollectionってどこにあります?
ぐぐったらC#のクラスは見つかりましたが
上に書いた通り、stop時の処理がまわりくどくなりそうなのを気にしてます
実行時のロジックがシンプルなやり方を追求したいです
783843
2020/05/08(金) 12:23:41.84ID:UXU8nfWQ784デフォルトの名無しさん
2020/05/08(金) 12:39:35.76ID:N+8ZKU+/ 普通は終了を意味する番兵オブジェクトを用意するんじゃないの
キューの中身を最後まで処理して欲しいなら単に番兵を積めばいいし、無理矢理終わらせたいならキューを強制的に空にしてから番兵放り込めばいい
キューの中身を最後まで処理して欲しいなら単に番兵を積めばいいし、無理矢理終わらせたいならキューを強制的に空にしてから番兵放り込めばいい
785デフォルトの名無しさん
2020/05/08(金) 13:50:27.60ID:Fn7VYFHg >>784
なるほどそれだときれいに書けますね
runningフラグは不要にできると
しかしわりとクリティカルな処理を想定してるので
stopを呼ぶスレッドで(イベントオブジェクトの)解放処理が起るのは問題に
なるかもしれないです(例ではintですが実際はもうちょっと凝った構造体)
runningフラグ前提だときれいに書けないですかね?
なるほどそれだときれいに書けますね
runningフラグは不要にできると
しかしわりとクリティカルな処理を想定してるので
stopを呼ぶスレッドで(イベントオブジェクトの)解放処理が起るのは問題に
なるかもしれないです(例ではintですが実際はもうちょっと凝った構造体)
runningフラグ前提だときれいに書けないですかね?
786デフォルトの名無しさん
2020/05/08(金) 17:13:05.00ID:+t+L26mC こんなんでいいのでは。running2回チェックは避けられそうにないなあ。チェックよろ
start() {
{
lock()
running = true
}
run(loop)
}
stop() {
{
lock()
running = false
}
notify()
join()
}
loop() {
lock()
while(true) {
cond_wait(!empty() or !running)
if (!running) {
break
}
pop()
}
}
start() {
{
lock()
running = true
}
run(loop)
}
stop() {
{
lock()
running = false
}
notify()
join()
}
loop() {
lock()
while(true) {
cond_wait(!empty() or !running)
if (!running) {
break
}
pop()
}
}
787デフォルトの名無しさん
2020/05/08(金) 17:29:10.43ID:NOJZfKLR スレッド動作トリガーはcond 1個にして
スレッド内で、キューやrunningフラグを見る
スレッド内で、キューやrunningフラグを見る
788デフォルトの名無しさん
2020/05/08(金) 17:32:31.56ID:NOJZfKLR Windowsみたいな高機能な同期が有れば
イベント、タイマー、ファイルアクセス、ネットワーク通信
などなど色々な物を同時にトリガーに出来る
linux系はその辺が貧弱
スレッドを動かす為のスレッドが必要になったりする
イベント、タイマー、ファイルアクセス、ネットワーク通信
などなど色々な物を同時にトリガーに出来る
linux系はその辺が貧弱
スレッドを動かす為のスレッドが必要になったりする
789デフォルトの名無しさん
2020/05/08(金) 17:46:30.97ID:+t+L26mC >>788
全部selectやepollでまとめて待てるけど、winはもっと高機能なん?
全部selectやepollでまとめて待てるけど、winはもっと高機能なん?
790デフォルトの名無しさん
2020/05/08(金) 18:43:53.40ID:NOJZfKLR yes
791デフォルトの名無しさん
2020/05/08(金) 19:10:58.40ID:Fn7VYFHg >>786
インデントつけました
void loop() {
lock()
while (true) {
cond_wait(!empty() or !running)
if (!running) {
break
}
pop()
}
}
cond_waitの前にrunningみなくて大丈夫ですかね?
startの直後loopが始まる直前でstopが呼ばれた場合cond_waitって起きます?
インデントつけました
void loop() {
lock()
while (true) {
cond_wait(!empty() or !running)
if (!running) {
break
}
pop()
}
}
cond_waitの前にrunningみなくて大丈夫ですかね?
startの直後loopが始まる直前でstopが呼ばれた場合cond_waitって起きます?
792デフォルトの名無しさん
2020/05/08(金) 19:27:16.63ID:V12mYFi1793デフォルトの名無しさん
2020/05/08(金) 20:07:48.20ID:DADrWmcq >>791
cond.waitはブロックする前に一度条件式を確認する動きになってる。
条件式が初めからtrueであればそもそもブロッキングをしないからcond.waitの前にrunningをみなくても大丈夫だと思う
cond.waitはブロックする前に一度条件式を確認する動きになってる。
条件式が初めからtrueであればそもそもブロッキングをしないからcond.waitの前にrunningをみなくても大丈夫だと思う
794デフォルトの名無しさん
2020/05/08(金) 20:36:08.72ID:Fn7VYFHg795デフォルトの名無しさん
2020/05/08(金) 22:51:30.97ID:Fn7VYFHg もうひとつ質問させてください
>>774 のrunningはstd::atomic_boolにする必要はあります?
C言語だとこの手の変数はvolatileにすると思うのですが
C++ならatomicでしょうか?
上の方でatomicのこといろいろ書いてありますがこの場合はどうなんでしょう?
>>774 のrunningはstd::atomic_boolにする必要はあります?
C言語だとこの手の変数はvolatileにすると思うのですが
C++ならatomicでしょうか?
上の方でatomicのこといろいろ書いてありますがこの場合はどうなんでしょう?
796デフォルトの名無しさん
2020/05/09(土) 00:53:16.27ID:8wHk9BWj void Foo::pushReq(const XXXReq& req)
{
EnterCriticalSection(&m_csec);
{
if (!m_bTerminate) {
m_requests.push(req);
SetEvent(m_hEvtNewRequest);
}
}
LeaveCriticalSection(&m_csec);
}
{
EnterCriticalSection(&m_csec);
{
if (!m_bTerminate) {
m_requests.push(req);
SetEvent(m_hEvtNewRequest);
}
}
LeaveCriticalSection(&m_csec);
}
797デフォルトの名無しさん
2020/05/09(土) 00:57:33.61ID:8wHk9BWj bool Foo::popReq(XXXReq& req)
for (;;) {
if (!m_bInOperation) {
// イベント待機
WaitForSingleObject(m_hEvtNewRequest, INFINITE);
if (m_bTerminate) {
return false;
}
m_bInOperation = true;
} else {
EnterCriticalSection(&m_csec);
{
if (m_requests.empty()) {
m_bInOperation = false;
// 今入っているイベントはbInProcess中に入ったもので
// 明らかに古いのでリセット
ResetEvent(m_hEvtNewRequest);
} else {
// 要求があればpopして処理
req = m_requests.front();
m_requests.pop();
}
}
LeaveCriticalSection(&m_csec);
if (m_bInOperation) {
// 処理すべきリクエスト有り
break;
}
}
}
}
for (;;) {
if (!m_bInOperation) {
// イベント待機
WaitForSingleObject(m_hEvtNewRequest, INFINITE);
if (m_bTerminate) {
return false;
}
m_bInOperation = true;
} else {
EnterCriticalSection(&m_csec);
{
if (m_requests.empty()) {
m_bInOperation = false;
// 今入っているイベントはbInProcess中に入ったもので
// 明らかに古いのでリセット
ResetEvent(m_hEvtNewRequest);
} else {
// 要求があればpopして処理
req = m_requests.front();
m_requests.pop();
}
}
LeaveCriticalSection(&m_csec);
if (m_bInOperation) {
// 処理すべきリクエスト有り
break;
}
}
}
}
798デフォルトの名無しさん
2020/05/09(土) 01:01:13.28ID:8wHk9BWj ウィンドーズの同期APIの仕様により
同期API呼び出し時点であらゆる変数のメモリへの書込みとメモリからの読み込みが完了するので
とくにvolatileは不要
なはず、
同期API呼び出し時点であらゆる変数のメモリへの書込みとメモリからの読み込みが完了するので
とくにvolatileは不要
なはず、
799デフォルトの名無しさん
2020/05/09(土) 06:06:39.41ID:1JWVR6vl >>795
>>786のようにrunningの更新をlockで保護するのであればatomic_boolにする必要はないと思うよ
void stop() {
std::lock_guard<std::mutex> lk(mtx);
running = false;
cond.notify_all();
}
お手本でも普通のboolを使ってる
https://cpprefjp.github.io/reference/condition_variable/condition_variable.html
https://cpprefjp.github.io/article/lib/how_to_use_cv.html
>>786のようにrunningの更新をlockで保護するのであればatomic_boolにする必要はないと思うよ
void stop() {
std::lock_guard<std::mutex> lk(mtx);
running = false;
cond.notify_all();
}
お手本でも普通のboolを使ってる
https://cpprefjp.github.io/reference/condition_variable/condition_variable.html
https://cpprefjp.github.io/article/lib/how_to_use_cv.html
800デフォルトの名無しさん
2020/05/09(土) 11:17:56.00ID:KZFWOt7Z >>799
loop()内のrunningは毎度メモリから読まれる必要があるので
C言語ならvolatileにすると理解しています
つまりループ内で最適化されてしまわないようにするためだと思います
これがC++だと仕様的にもともと問題ないのでしょうか?
逆に最適化がかかりにくくなってしまう気がします
ただ手元で実装したものは最適化かけていても確かに期待通り動いています
loop()内のrunningは毎度メモリから読まれる必要があるので
C言語ならvolatileにすると理解しています
つまりループ内で最適化されてしまわないようにするためだと思います
これがC++だと仕様的にもともと問題ないのでしょうか?
逆に最適化がかかりにくくなってしまう気がします
ただ手元で実装したものは最適化かけていても確かに期待通り動いています
801デフォルトの名無しさん
2020/05/09(土) 12:59:28.79ID:1JWVR6vl >>800
POSIX準拠のシステムでは同時アクセスを防ぐ書き方(mutexによるlockとかstd::atomicによるstore/loadとか)
をすれば自動的にメモリ同期(メモリへのフラッシュ)が行われる作りになっていてvolatileとかを気にする必要がないらしい
https://yupo5656.hatenadiary.org/entry/20040618/p2
POSIX準拠のシステムでは同時アクセスを防ぐ書き方(mutexによるlockとかstd::atomicによるstore/loadとか)
をすれば自動的にメモリ同期(メモリへのフラッシュ)が行われる作りになっていてvolatileとかを気にする必要がないらしい
https://yupo5656.hatenadiary.org/entry/20040618/p2
802デフォルトの名無しさん
2020/05/09(土) 13:06:53.14ID:8wHk9BWj >>800
>>774のコードの全体の当否はおくとして
while()の中でlockしているのであればlockされるブロックに出入りする際に
>runningは毎度メモリから読まれる
が実現されるからrunningフラグはvolatile無しでもむ無問題、
C++の標準的なlockの仕様は知らんがlockに出入りするときに
CPUのライトキューやリードキューに未処理のライトコマンドやリードコマンドが乗ったままだと
正しいロックにならないから普通のlockの実装ではメモリバリアを行う
メモリバリアはコンパイラに対してはイントリンシックな関数か何かとして定義されており、
それらの呼び出しのときコンパイラは空気を読んでレジスタに乗ったままの変数を放置しないはず…
(変数に対する副作用がある関数呼び出しとみなす
>>774のコードの全体の当否はおくとして
while()の中でlockしているのであればlockされるブロックに出入りする際に
>runningは毎度メモリから読まれる
が実現されるからrunningフラグはvolatile無しでもむ無問題、
C++の標準的なlockの仕様は知らんがlockに出入りするときに
CPUのライトキューやリードキューに未処理のライトコマンドやリードコマンドが乗ったままだと
正しいロックにならないから普通のlockの実装ではメモリバリアを行う
メモリバリアはコンパイラに対してはイントリンシックな関数か何かとして定義されており、
それらの呼び出しのときコンパイラは空気を読んでレジスタに乗ったままの変数を放置しないはず…
(変数に対する副作用がある関数呼び出しとみなす
803デフォルトの名無しさん
2020/05/09(土) 13:16:40.60ID:2pLCfdPK POSIXスレッドはetchになってからようやく使い物になった
woody以前は酷い出来だったのは酔い思い出
woody以前は酷い出来だったのは酔い思い出
804デフォルトの名無しさん
2020/05/09(土) 13:46:46.99ID:8wHk9BWj しかし以下のような実装のときrunningにvolatileが本当に要らないかどうかわわからん…
void bar() { (内部でlockを行う) }
====↓↓↓異なる翻訳単位↓↓↓====
void foo {
bool running = false; // runningはローカル変数
while (running) {
bar(); // 一見runninguへの副作用が考えられないシグネチャ
}
}
どうやっているのかは知らんが、ウィンドーズの同期系API(上の例でbar()にあたる)は
うまいことやってくれる(と思う!
void bar() { (内部でlockを行う) }
====↓↓↓異なる翻訳単位↓↓↓====
void foo {
bool running = false; // runningはローカル変数
while (running) {
bar(); // 一見runninguへの副作用が考えられないシグネチャ
}
}
どうやっているのかは知らんが、ウィンドーズの同期系API(上の例でbar()にあたる)は
うまいことやってくれる(と思う!
806デフォルトの名無しさん
2020/05/09(土) 13:52:06.16ID:8wHk9BWj よく考えたら上のコードではrunningへのポインタを他のスレッドが知っていることもありえないから、
そういう意味でvolatile不要(最適化上等)か…orz
一方、runningがグローバル変数なら、異なる翻訳系で定義された関数を呼び出した後に、
runningは改めてメモリから読まれることはコンパイラが生成するコードの規定の動作なので
volatile不要
まとめると、runningがグローバル変数でありかつ同期目的の関数内でメモリフェンスしており、
かつそこが毎回通る限り、runningにvolatileは不要
そういう意味でvolatile不要(最適化上等)か…orz
一方、runningがグローバル変数なら、異なる翻訳系で定義された関数を呼び出した後に、
runningは改めてメモリから読まれることはコンパイラが生成するコードの規定の動作なので
volatile不要
まとめると、runningがグローバル変数でありかつ同期目的の関数内でメモリフェンスしており、
かつそこが毎回通る限り、runningにvolatileは不要
807デフォルトの名無しさん
2020/05/09(土) 13:53:07.30ID:VRhqXw8t >>804
running がローカル変数なら bar() での副作用は無理だから volatile の有無によらず foo() は空にできちゃうのでは?
running がローカル変数なら bar() での副作用は無理だから volatile の有無によらず foo() は空にできちゃうのでは?
808デフォルトの名無しさん
2020/05/09(土) 13:54:44.10ID:VRhqXw8t (リロードしてなかった・・・)
>>806 つまり volatile が必要なケースは無いね?
>>806 つまり volatile が必要なケースは無いね?
809デフォルトの名無しさん
2020/05/09(土) 14:01:00.47ID:8wHk9BWj810デフォルトの名無しさん
2020/05/09(土) 14:22:58.21ID:KZFWOt7Z811デフォルトの名無しさん
2020/05/09(土) 14:32:48.74ID:KZFWOt7Z >>802
> >>800
> >>774のコードの全体の当否はおくとして
> while()の中でlockしているのであればlockされるブロックに出入りする際に
> >runningは毎度メモリから読まれる
> が実現されるからrunningフラグはvolatile無しでもむ無問題、
一度目はメモリから読まれるのは確実だと思います
ただループの場合、2度目のリードからはコンパイラが最適化をかけて
一度目の値を使いまわす可能性があると思います
void loop()
{
unique_lock lock(mtx);
auto r = running
while (r) {
....
}
}
と置き換えてしまう可能性があるのでは?ということを心配しています
私のC言語開発の経験ではこの場合はvolatileにするのが鉄則でした
c++のコンパイラはかしこくrunningは都度メモリから読み出すべしと判断していると
なるとその判定はどうやって行っているのでしょう?
一律にローカル変数以外はメモリから呼び出すわけではないと思います
(それだとかなり性能が落ちると思います)
> >>800
> >>774のコードの全体の当否はおくとして
> while()の中でlockしているのであればlockされるブロックに出入りする際に
> >runningは毎度メモリから読まれる
> が実現されるからrunningフラグはvolatile無しでもむ無問題、
一度目はメモリから読まれるのは確実だと思います
ただループの場合、2度目のリードからはコンパイラが最適化をかけて
一度目の値を使いまわす可能性があると思います
void loop()
{
unique_lock lock(mtx);
auto r = running
while (r) {
....
}
}
と置き換えてしまう可能性があるのでは?ということを心配しています
私のC言語開発の経験ではこの場合はvolatileにするのが鉄則でした
c++のコンパイラはかしこくrunningは都度メモリから読み出すべしと判断していると
なるとその判定はどうやって行っているのでしょう?
一律にローカル変数以外はメモリから呼び出すわけではないと思います
(それだとかなり性能が落ちると思います)
812デフォルトの名無しさん
2020/05/09(土) 14:56:31.18ID:8wHk9BWj >>811
コンパイラ視点で見れば中身のわからないcond.wait()と言う関数呼び出しが
グローバル変数runningに対する副作用を持たない(値を書き換えない)ことの保証が無いから、
cond.wait()をループ外にくくりだす最適化が行われることは普通は無い。 --- (A)
また、ソースコード上cond.wait()を呼び出した後にrunningを参照する箇所があれば、
普通はかならずメモリからrunningを読み直すコードが吐かれる --- (B)
普通でない場合というのはコンパイラがcond.wait()メソッドの中身まで知っていて
runningに対する副作用が無いと結論付ける場合が考えられるが、
それでもcond.wait()の中で
(1) メモリバリアを行っており、
(2) その意味をコンパイラが知っている
限り、コンパイラが「(cond.wait()呼び出しによる)runningに対する副作用が無い」と結論付けることはありえない --- (C)
というわけで、普通は(A)、(B)が成立するからrunningのvolatileは不要
(A)、(B)非成立な変に賢いコンパイラでも、(1)と(2)が成立するなら(C)が成立するからrunningのvolatileは不要
コンパイラ視点で見れば中身のわからないcond.wait()と言う関数呼び出しが
グローバル変数runningに対する副作用を持たない(値を書き換えない)ことの保証が無いから、
cond.wait()をループ外にくくりだす最適化が行われることは普通は無い。 --- (A)
また、ソースコード上cond.wait()を呼び出した後にrunningを参照する箇所があれば、
普通はかならずメモリからrunningを読み直すコードが吐かれる --- (B)
普通でない場合というのはコンパイラがcond.wait()メソッドの中身まで知っていて
runningに対する副作用が無いと結論付ける場合が考えられるが、
それでもcond.wait()の中で
(1) メモリバリアを行っており、
(2) その意味をコンパイラが知っている
限り、コンパイラが「(cond.wait()呼び出しによる)runningに対する副作用が無い」と結論付けることはありえない --- (C)
というわけで、普通は(A)、(B)が成立するからrunningのvolatileは不要
(A)、(B)非成立な変に賢いコンパイラでも、(1)と(2)が成立するなら(C)が成立するからrunningのvolatileは不要
813デフォルトの名無しさん
2020/05/09(土) 15:08:39.92ID:1JWVR6vl814デフォルトの名無しさん
2020/05/09(土) 15:08:46.08ID:KZFWOt7Z >>812
それはstd:::condition_variableを使った場合に限定していますか?
基本的にpthreadのwrapperだと思うのですが、仮にコンパイラがそれを特別扱いしているとすると
pthreadをダイレクトに使った場合はどうなりますか?
あと客観的な文献を示してほしいです
それはstd:::condition_variableを使った場合に限定していますか?
基本的にpthreadのwrapperだと思うのですが、仮にコンパイラがそれを特別扱いしているとすると
pthreadをダイレクトに使った場合はどうなりますか?
あと客観的な文献を示してほしいです
815デフォルトの名無しさん
2020/05/09(土) 15:11:10.97ID:KZFWOt7Z816デフォルトの名無しさん
2020/05/09(土) 15:20:05.99ID:1JWVR6vl817デフォルトの名無しさん
2020/05/09(土) 15:38:10.36ID:8wHk9BWj >>814
>それはstd:::condition_variableを使った場合に限定していますか?
いいえ
>pthreadをダイレクトに使った場合はどうなりますか?
どう使うつもりかわわからんが、コンパイラに中身を知りようが無い関数の
呼び出しがループ内に生じる限り同じ話
>客観的な文献を示してほしいです
(1) 変数に対する副作用がある(かもしれない)関数がループ外にくくりだされないこと
コンパイラはソースコードをオブジェクトコードに翻訳する際、
ソースコードに書かれたアルゴリズム(有限ステップで終わる&非同期要素無し)の
動作結果を変えてはならない。この原則はコンパイラの教科書に書いてあるし常識と言っても過言ではない
で、変数に対する副作用がある(かもしれない)関数の不適切な最適化はこの原則にひっかかる
(2) 少なくともMSVCがメモリバリアの意味を知っている根拠
https://docs.microsoft.com/ja-jp/cpp/intrinsics/readwritebarrier?view=vs-2015
これ、VS2010までは非推奨ではなかったし、サンプルコードも載っていたが無くなってたorz
>それはstd:::condition_variableを使った場合に限定していますか?
いいえ
>pthreadをダイレクトに使った場合はどうなりますか?
どう使うつもりかわわからんが、コンパイラに中身を知りようが無い関数の
呼び出しがループ内に生じる限り同じ話
>客観的な文献を示してほしいです
(1) 変数に対する副作用がある(かもしれない)関数がループ外にくくりだされないこと
コンパイラはソースコードをオブジェクトコードに翻訳する際、
ソースコードに書かれたアルゴリズム(有限ステップで終わる&非同期要素無し)の
動作結果を変えてはならない。この原則はコンパイラの教科書に書いてあるし常識と言っても過言ではない
で、変数に対する副作用がある(かもしれない)関数の不適切な最適化はこの原則にひっかかる
(2) 少なくともMSVCがメモリバリアの意味を知っている根拠
https://docs.microsoft.com/ja-jp/cpp/intrinsics/readwritebarrier?view=vs-2015
これ、VS2010までは非推奨ではなかったし、サンプルコードも載っていたが無くなってたorz
818デフォルトの名無しさん
2020/05/09(土) 15:40:22.80ID:VRhqXw8t >>814
標準スレッドライブラリを使った前後の読み書きについては、
ライブラリ関数呼び出し( lock/unlock など)が提供するスレッドをまたぐ "synchronize with" 関係と
スレッド内での, "sequenced before/after" による前後関係とをつないだ
"inter-thread happens before" 関係(順序付け)に基づく挙動が規定されている。
https://timsong-cpp.github.io/cppwp/n4659/intro.multithread#intro.races-9
>811 のような書き換えは許されない。
規格化以前の pthread などをダイレクトに使った場合は >>812 の挙げるような
「事実上問題にならない」に頼ることになり、これに volatile を加えても「事実上問題にならない」の
範疇であることに変わりはない。
問題の可能性が減ったり、実際に起こっていた問題の解決につながることはあっただろうけどね。
これについては「客観的な文献」といったものが無かったことも規格化の動機になっただろう。
https://isocpp.org/wiki/faq/cpp11#cpp11-specific-goals
> - Machine model and concurrency ? provide stronger guarantees for and better facilities
> for using modern hardware (e.g. multicores and weakly coherent memory models). ...
標準スレッドライブラリを使った前後の読み書きについては、
ライブラリ関数呼び出し( lock/unlock など)が提供するスレッドをまたぐ "synchronize with" 関係と
スレッド内での, "sequenced before/after" による前後関係とをつないだ
"inter-thread happens before" 関係(順序付け)に基づく挙動が規定されている。
https://timsong-cpp.github.io/cppwp/n4659/intro.multithread#intro.races-9
>811 のような書き換えは許されない。
規格化以前の pthread などをダイレクトに使った場合は >>812 の挙げるような
「事実上問題にならない」に頼ることになり、これに volatile を加えても「事実上問題にならない」の
範疇であることに変わりはない。
問題の可能性が減ったり、実際に起こっていた問題の解決につながることはあっただろうけどね。
これについては「客観的な文献」といったものが無かったことも規格化の動機になっただろう。
https://isocpp.org/wiki/faq/cpp11#cpp11-specific-goals
> - Machine model and concurrency ? provide stronger guarantees for and better facilities
> for using modern hardware (e.g. multicores and weakly coherent memory models). ...
819デフォルトの名無しさん
2020/05/09(土) 16:27:23.02ID:KZFWOt7Z >>817
なるほど
つまりc/c++コンパイラの最適化において、
副作用がある(pure functionでない)関数があると、それをまたいだ
リオーダーや値の流用をすることはない
当然メモリバリアを張るcond(pthreadも含む)は副作用ありなので
これがループ中に存在する場合はrunningは毎度メモリから読み出されることになる
ということですね
非常によくわかりました
なるほど
つまりc/c++コンパイラの最適化において、
副作用がある(pure functionでない)関数があると、それをまたいだ
リオーダーや値の流用をすることはない
当然メモリバリアを張るcond(pthreadも含む)は副作用ありなので
これがループ中に存在する場合はrunningは毎度メモリから読み出されることになる
ということですね
非常によくわかりました
820デフォルトの名無しさん
2020/05/09(土) 16:30:24.63ID:KZFWOt7Z >>817
しかし、この場合volatileが不要といえることはわかりましたが、
これはあくまで副作用あり関数の存在に依存しています
と考えると一般的にはvolatileはつけておく方習慣の方がやはり無難だと思いますがいかがでしょう?
(c++ならatomicに置き換えるとして)
しかし、この場合volatileが不要といえることはわかりましたが、
これはあくまで副作用あり関数の存在に依存しています
と考えると一般的にはvolatileはつけておく方習慣の方がやはり無難だと思いますがいかがでしょう?
(c++ならatomicに置き換えるとして)
821デフォルトの名無しさん
2020/05/09(土) 16:33:07.67ID:KZFWOt7Z822デフォルトの名無しさん
2020/05/09(土) 16:41:37.74ID:8wHk9BWj >>819
レジスタに載ったままな変数の流用はともかく、
リオーダーは副作用がある(pure functionでない)関数をまたいでも特に阻害されないんじゃね;
リオーダーの効果はプログラムの実行に関して普通の状況では透過的なので、普通の状況でコンパイラがそれをやめさせる理由が無い
普通でない状況としては>>714みたく同一データに対する複数コアからの同時アクセスがありえるケース
(コンパイラが知りようが無い非同期事象が生じるケース)があるが、
これは(ユーザーコードかライブラリの)プログラマがメモリバリアを明示的に書き、
コンパイラが空気を呼んでその前後の変数の流用も抑止することで処置される
と思うが真実は知らん
気分としてはあくまで>>800の立場であって非同期の問題に関してはノーコメント
事実として出来上がったプログラムが正しく動いているなら問題ないのじゃガッハッハッハ、
レジスタに載ったままな変数の流用はともかく、
リオーダーは副作用がある(pure functionでない)関数をまたいでも特に阻害されないんじゃね;
リオーダーの効果はプログラムの実行に関して普通の状況では透過的なので、普通の状況でコンパイラがそれをやめさせる理由が無い
普通でない状況としては>>714みたく同一データに対する複数コアからの同時アクセスがありえるケース
(コンパイラが知りようが無い非同期事象が生じるケース)があるが、
これは(ユーザーコードかライブラリの)プログラマがメモリバリアを明示的に書き、
コンパイラが空気を呼んでその前後の変数の流用も抑止することで処置される
と思うが真実は知らん
気分としてはあくまで>>800の立場であって非同期の問題に関してはノーコメント
事実として出来上がったプログラムが正しく動いているなら問題ないのじゃガッハッハッハ、
823デフォルトの名無しさん
2020/05/09(土) 16:43:21.63ID:8wHk9BWj824デフォルトの名無しさん
2020/05/09(土) 17:00:35.76ID:1JWVR6vl >>820
複数スレッドで共有する変数を読み込む以上絶対にlockなりatomicなりを使うわけだから必ず副作用あり関数が存在する
複数スレッドで共有する変数を読み込む以上絶対にlockなりatomicなりを使うわけだから必ず副作用あり関数が存在する
825はちみつ餃子 ◆8X2XSCHEME
2020/05/09(土) 18:56:58.72ID:MmeKQuXy >>820
見かけ上の挙動が仕様通りだったらどうコンパイルしてもよいというのが言語としての基本的なルール。
https://timsong-cpp.github.io/cppwp/n3337/intro.execution
昔は並列実行に関する動作モデルの既定がなかったので、
既定にないことをするプログラムを書いたときに
最適化で除去されたり順序が入れ替わったりしてもそれは仕様通りだったんだよ。
volatile はプログラムとして書いてある通りのことを (たとえ観測できなくても) 実際の動作にも
反映させろというヒントをコンパイラに伝えるものではあるけど、
言語仕様の記述に用いられる抽象機械と実際の実行環境が完全にマッピングできるわけでもない
から volatile が具体的にどう影響するかってのは分からん。
言語仕様外のことをするときのために用意されていると考えてもいい。
つまり、ロックやアトミックまわりの仕様で規定されていることなら volatile を付けようが付けまいが
その通りになるし、既定されていないことなら volatile を付けても言語仕様として得られる保証は何もない。
処理系として言語仕様以上の保証を付けているということはあるだろうけど。
見かけ上の挙動が仕様通りだったらどうコンパイルしてもよいというのが言語としての基本的なルール。
https://timsong-cpp.github.io/cppwp/n3337/intro.execution
昔は並列実行に関する動作モデルの既定がなかったので、
既定にないことをするプログラムを書いたときに
最適化で除去されたり順序が入れ替わったりしてもそれは仕様通りだったんだよ。
volatile はプログラムとして書いてある通りのことを (たとえ観測できなくても) 実際の動作にも
反映させろというヒントをコンパイラに伝えるものではあるけど、
言語仕様の記述に用いられる抽象機械と実際の実行環境が完全にマッピングできるわけでもない
から volatile が具体的にどう影響するかってのは分からん。
言語仕様外のことをするときのために用意されていると考えてもいい。
つまり、ロックやアトミックまわりの仕様で規定されていることなら volatile を付けようが付けまいが
その通りになるし、既定されていないことなら volatile を付けても言語仕様として得られる保証は何もない。
処理系として言語仕様以上の保証を付けているということはあるだろうけど。
826デフォルトの名無しさん
2020/05/09(土) 18:58:03.61ID:KZFWOt7Z >>824
確かに、正しく排他制御しているのならばそれはいえそうです
確かに、正しく排他制御しているのならばそれはいえそうです
827デフォルトの名無しさん
2020/05/09(土) 19:14:29.09ID:TBKnesgm volatileは簡潔に言うとregisterの逆の作用だね
828デフォルトの名無しさん
2020/05/09(土) 22:27:01.93ID:IGvav/BT volatileはコンパイラに、コード通り読み書きを行うコードを吐けと指示するだけ
CPUが勝手に順番を変えたりしないようにCPUに指示をする命令は別途行わなければならない
x86の場合は何もしなくて良い場合が多く
ARMの場合は追加しなければならない場合が多い
CPUが勝手に順番を変えたりしないようにCPUに指示をする命令は別途行わなければならない
x86の場合は何もしなくて良い場合が多く
ARMの場合は追加しなければならない場合が多い
829デフォルトの名無しさん
2020/05/09(土) 22:31:00.74ID:TVkAIoUw いいえ、単に昔からGCCが糞なだけです。
830デフォルトの名無しさん
2020/05/09(土) 22:42:09.15ID:G+eyUkVB 最近日本式のやつが再注目されてるじゃないか。
それは欧州式のやつのことじゃないか?
それは欧州式のやつのことじゃないか?
831843
2020/05/09(土) 23:22:12.13ID:NXsGMAUL >>824
片方は書き出し、もう一方は読み出しだけなら排他制御しなくてもアトミックでありさえすれば大丈夫だし、そういう実装はそれなりにあるよ
片方は書き出し、もう一方は読み出しだけなら排他制御しなくてもアトミックでありさえすれば大丈夫だし、そういう実装はそれなりにあるよ
832デフォルトの名無しさん
2020/05/10(日) 02:46:29.69ID:EdgxbLB4 可変長引数テンプレートから型の文字列を組み合わせて配列を定数化して取り出せるようにするために
以下のようなコードを書いたのですが、
template<typename ... ComponentsData> struct ComponentTypeGroup {
static constexpr std::size_t ComponentCount = sizeof...( ComponentsData );
static constexpr std::string_view TypeTexts[ComponentCount];
template<typename Type> constexpr void TypeGroupText( std::size_t _uIndex ) {
TypeTexts[_uIndex] = Detail::Nameof<Type>(); // 定数文字列を生成する関数です。
}
template<typename First, typename Second, typename ... ArgTypes> constexpr void TypeGroupText( std::size_t _uIndex ) {
TypeGroupText<First>( _uIndex );
TypeGroupText<Second, ArgTypes...>( _uIndex + 1 );
}
constexpr ComponentGroup(){ TypeGroupText<ComponentsData...>( 0 ); }
};
constexpr ComponentGroup()で「型指定子がありません」と出てコンパイルエラーが取れません。
何故このエラーが出ているのかがいまいちわからず、途方に暮れています。
誰かご教授いただけないでしょうか?
以下のようなコードを書いたのですが、
template<typename ... ComponentsData> struct ComponentTypeGroup {
static constexpr std::size_t ComponentCount = sizeof...( ComponentsData );
static constexpr std::string_view TypeTexts[ComponentCount];
template<typename Type> constexpr void TypeGroupText( std::size_t _uIndex ) {
TypeTexts[_uIndex] = Detail::Nameof<Type>(); // 定数文字列を生成する関数です。
}
template<typename First, typename Second, typename ... ArgTypes> constexpr void TypeGroupText( std::size_t _uIndex ) {
TypeGroupText<First>( _uIndex );
TypeGroupText<Second, ArgTypes...>( _uIndex + 1 );
}
constexpr ComponentGroup(){ TypeGroupText<ComponentsData...>( 0 ); }
};
constexpr ComponentGroup()で「型指定子がありません」と出てコンパイルエラーが取れません。
何故このエラーが出ているのかがいまいちわからず、途方に暮れています。
誰かご教授いただけないでしょうか?
833デフォルトの名無しさん
2020/05/10(日) 02:51:01.26ID:KxiPn0ce ComponentTypeGroupのtypoでなくて?
834デフォルトの名無しさん
2020/05/10(日) 03:20:50.69ID:s7BT3+bq まずそのインターコンチネンタルホテルみたいな長ったらしい名前やめろ
835デフォルトの名無しさん
2020/05/10(日) 03:25:28.56ID:wE52EU/R 古いコードの一時的メンテのため、stdとstd::tr1をC++11で混在させて使う話なんですが、
元々C++11以前のコンパイラ用に書かれた
using namespace std;
using std::tr1::shared_ptr;
shared_ptr<Hoge> hoge = ...
みたいなコードをC++11でビルドすると、C++11には std::shared_ptr があり ambiguous エラーになりますよね。
最初 share_ptr を std::shared_ptr ということにしてビルドしようかと思ったら、ところどころ std::tr1::shared_ptr と
フル宣言してあり面倒なことが判明。なので shared_ptr は std::str1::shared_ptr とみなす方針に戻りました。
なので using namepace std; を保持しつつ shared_ptr を std::tr1::shared_ptr としてビルドしたいんですが、
それって可能でしょうか? 例えば using namespace std; で std::shared_ptr を除外するようなことってできます?
古いコードを出来るだけいじらずビルドしたい、というのが一番のポイントですw
元々C++11以前のコンパイラ用に書かれた
using namespace std;
using std::tr1::shared_ptr;
shared_ptr<Hoge> hoge = ...
みたいなコードをC++11でビルドすると、C++11には std::shared_ptr があり ambiguous エラーになりますよね。
最初 share_ptr を std::shared_ptr ということにしてビルドしようかと思ったら、ところどころ std::tr1::shared_ptr と
フル宣言してあり面倒なことが判明。なので shared_ptr は std::str1::shared_ptr とみなす方針に戻りました。
なので using namepace std; を保持しつつ shared_ptr を std::tr1::shared_ptr としてビルドしたいんですが、
それって可能でしょうか? 例えば using namespace std; で std::shared_ptr を除外するようなことってできます?
古いコードを出来るだけいじらずビルドしたい、というのが一番のポイントですw
836デフォルトの名無しさん
2020/05/10(日) 03:46:29.57ID:oMXEUzlE 単に#include<tr1/memory>してstd::tr1::shared_ptrのusingを消すんではあかんの?
新しいコンパイラではstd::shared_ptrとstd::tr1::shared_ptrって同じものでしょ
新しいコンパイラではstd::shared_ptrとstd::tr1::shared_ptrって同じものでしょ
837デフォルトの名無しさん
2020/05/10(日) 05:06:37.17ID:wE52EU/R >>836
using std::tr1::shared_ptrを取るとただのshared_ptrはstd::shared_ptrになります (using namespace std)。
すると今回の場合、
std::tr1::shared_ptr<Hoge> boge; // たまにちゃんと名前空間を使ってる宣言がある
boge = shared_ptr<Hoge>(new Hoge);
みたいなコードが駄目になるようですが。
std::tr1::shared_ptrとstd::shared_ptrはとりあえず名前としては違うんじゃないですか? 違うとコンパイラー
が認識しているように見えますが。
using std::tr1::shared_ptrを取るとただのshared_ptrはstd::shared_ptrになります (using namespace std)。
すると今回の場合、
std::tr1::shared_ptr<Hoge> boge; // たまにちゃんと名前空間を使ってる宣言がある
boge = shared_ptr<Hoge>(new Hoge);
みたいなコードが駄目になるようですが。
std::tr1::shared_ptrとstd::shared_ptrはとりあえず名前としては違うんじゃないですか? 違うとコンパイラー
が認識しているように見えますが。
838デフォルトの名無しさん
2020/05/10(日) 11:05:22.30ID:sYQDYC6t 淫乱チンポメンタルヘルス?
>>838
それ、面白いと思ったのですか?
それ、面白いと思ったのですか?
840デフォルトの名無しさん
2020/05/10(日) 11:25:22.96ID:5OK5MvZd841デフォルトの名無しさん
2020/05/10(日) 11:49:35.32ID:sYQDYC6t インサートチンポレンタルホテル!
842デフォルトの名無しさん
2020/05/10(日) 12:12:32.27ID:6Ru0pW3/ >>840
> namespace std { namespace tr1 = ::std; }
おお、これで std名前空間の中に tr1 のエイリアスを定義できる感じですか?
結果 std::tr1 は ::std -> std を指す、と。
> namespace std { namespace tr1 = ::std; }
おお、これで std名前空間の中に tr1 のエイリアスを定義できる感じですか?
結果 std::tr1 は ::std -> std を指す、と。
843デフォルトの名無しさん
2020/05/10(日) 12:19:21.29ID:KGOVLWXM844デフォルトの名無しさん
2020/05/10(日) 12:49:31.40ID:uBqrUzQt コンストラクタの綴り間違えているんじゃね?
何れにしろconstexpr static memberをコンストラクタやメンバ関数内で初期化は出来ないと思うが。
やるならstatic constexpr member関数の戻り値で初期化するとかしないと
何れにしろconstexpr static memberをコンストラクタやメンバ関数内で初期化は出来ないと思うが。
やるならstatic constexpr member関数の戻り値で初期化するとかしないと
■ このスレッドは過去ログ倉庫に格納されています
