0からの、超初心者C++相談室

0001デフォルトの名無しさん2018/11/12(月) 14:55:13.35ID:Tf74ZWQr
何にも知らない0からの出発、超初心者のためのC++相談室

0784デフォルトの名無しさん2024/02/03(土) 22:40:06.88ID:mzdZy5dk
>>782
あーそういうことですね。ありがとう。

07857742024/02/04(日) 02:54:38.53ID:1VXaeA8L
>>783 上は={}で通るのは確認してました。{}付けるとX型に見なされてコピーコンストラクタで初期化されるで合ってますか?
下の方、typenameの所は余りよく分からなかったですが強制的に引数の型で包んで(オブジェクト生成?)、コンストラクタの引数代入時に変換追加するということでいいですか?
typename以下はdecltype(f_)((f_))でも良いんかなと思って変更してみたら通りました

0786はちみつ餃子 ◆8X2XSCHEME 2024/02/04(日) 09:54:01.38ID:/H29LerN
>>785
> {}付けるとX型に見なされてコピーコンストラクタで初期化されるで合ってますか?

いいえ。 直接初期化に該当します。
コピー (コピーコンストラクタの起動) は発生しません。
つまり X x1(f0); と書いた場合と同じということです。
ですから暗黙の変換を一段階すれば充分なのでエラーなく通ります。

> コンストラクタの引数代入時に変換追加するということでいいですか?

いいえ。 何もしません。
コンパイルを通すためには不要ですので、 X のコンストラクタは

template <class T>
X(const T& f_) : f(f_) {}

という定義だけでも問題なく動作します。

ただ、こうすると T は「あらゆる型」になりえます。
std::function<void()> に変換不可能な型も受け入れてしまうということです。
変換不可能であればいずれにしても最終的にはエラーなのですが、
X がデタラメな型も受け入れてから F に変換失敗してエラーになるよりは
特定の条件を満たす型以外を X が拒否するほうが一般的には都合がよいので
そうなるようにしたのです。

コンパイルを通すために必要なのではなく通さないための処置です。

07877742024/02/04(日) 22:33:14.16ID:1VXaeA8L
>>786 上:初期化周りは似たような物が色々あって知識が曖昧でした。
下:あの記述は型制限の為ですか。読んでも意図がよく分からなかったので助かります。
説明ありがとうございました

0788デフォルトの名無しさん2024/02/10(土) 13:14:08.12ID:KJGevrBa
質問なのですがstd::coutに対する
 (a) 固定小数点表示
 (b) 小数以下精度指定(例えば20桁
 (c) setw()される表示幅に対し足りない上位桁0埋め
という表示仕様への変更と復旧は、変更が
 auto sv_flags = cout.flags(); cout << std::fixed; // (1)
 auto sv_prec = cout.precision(std::streamsize(20)); // (2)
 auto sv_fill = cout.fill(); cout << std::setfill('0'); // (3)
復旧が
 cout.flags(sv_flags); // (1)の変更から復旧
 cout.precision(sv_prec); // (2)の変更から復旧
 cout << setfill(sv_fill); // (3)の変更から復旧
と書くのが普通?シグネチャが不統一な印象があるますがもっとズバっとやる方法は無いもの?
((1)は変更にcoutのメソッドとマニピュレータが両方要り、復旧はcoutのメソッド。
 (2)は変更も復旧もcoutのメソッドで済む。(3)は変更が(1)と同じパティーンで復旧がマニピュレータ……

0789はちみつ餃子 ◆8X2XSCHEME 2024/02/10(土) 14:30:14.27ID:XEL9SE6k
>>788
・ 直接的に入出力を司るのはバッファと呼ばれるオブジェクト
  (たとえば basic_streambuf など)
・ ストリームには対応するバッファがセットされている (あまりバッファを直接には操作しない)
・ 書式はストリームの状態として保持されている

つまり同じバッファ (出力先) に対して異なるストリームをかぶせることが出来る。
一時的にだけ書式を変更するのであれば一時的なストリームを作るという方法がとれる。
コードで例を出すならこんな感じ。

#include <iostream>

int main() {
std::cout << 0.1 << std::endl;
{
std::ostream temp(std::cout.rdbuf());
temp.precision(30);
temp << 0.2 << std::endl;
temp << 0.3 << std::endl;
}
std::cout << 0.4 << std::endl;
}

書式をストリームの状態として持つのがすこぶる不格好だというのは
C++er にとっての共通認識になっていてようやく C++23 から std::print が導入されたので
モダンな C++ を使えるならそっちを使ったほうが良い。
std::format なら C++20 から。

0790デフォルトの名無しさん2024/02/10(土) 15:00:10.91ID:KJGevrBa
>>789
㌧クスなるほど……
変更した書式の戻し忘れが無く、問題らしい問題点はほぼ無しで良さげ……
(しいて言えばstreamの中の作りを理解していなければtempが何の目的でそうするのかわかりにくい(コメント必須)なだけ、

std::printは手元のVC++がまだC++20対応止まりなので当面見送らざるおえない

std::formatは…… 書式文字列が定数式限定という仕様のはいかがなものか……
今回の用途では困りませんし、コンパイル時に書式の妥当性をチェックしてくれるのは良いのですだが、
仮に、C言語における自作printf()様インターフェースの関数(書式文字列と可変長引数を変数で受け取り、内部でvprintf()を呼ぶ)
みたいなものを作りたくなった場合どうするんじゃとそこはかとなく疑問が……

0791はちみつ餃子 ◆8X2XSCHEME 2024/02/10(土) 15:16:22.24ID:XEL9SE6k
>>790
実行時バージョンとして std::vformat も用意されている。

0792デフォルトの名無しさん2024/02/10(土) 15:25:38.54ID:KJGevrBa
>>791
なるほどなるほど、自作std::format()様関数は問題無く作成でき、
書式文字列が定数式限定が困るというのは杞憂ですたねサーセン;;;
(実行時にならないと書式文字列が決まらない場合、コンパイル時チェックが原理的に不可能になるのはC言語のprintf()/vprintf()の関係も同じなのでC言語からの後退ではない

0793はちみつ餃子 ◆8X2XSCHEME 2024/02/10(土) 16:29:24.58ID:XEL9SE6k
メンバとして copyfmt があって、これで書式を他のストリームにコピーすることも出来る。
書式を待避しておくだけのストリームを作ってそれにコピーしておいて
後で元に戻すという使い方をしてもいいんだけど、
どうせストリームをあらたに作るならそれを一時的なストリームとして使ったほうが自然かと思う。

0794デフォルトの名無しさん2024/02/11(日) 22:38:22.35ID:smEWrSvv
std::setのinsertで

std::set<int> c1 = {1,2,3};
std::set<int> c2;

c2.insert(c1);

と書けると便利に思えますが解説のページを見るとできないようです。
なぜですか。

0795デフォルトの名無しさん2024/02/11(日) 22:45:16.04ID:KNbj1ANO
>>794
c2.insert(c1.begin (), c1.end ());

0796はちみつ餃子 ◆8X2XSCHEME 2024/02/12(月) 11:50:11.55ID:4VueJhli
>>794
set に set を insert できる「だけ」ってのはあまり便利ではない。
集合というものをより汎用的に扱える枠組みとして C++20 から range という概念が導入された。
その枠組みを上手いこと成立させる言語機能 concept が長いこと検討されてて、
入る入ると言いながら C++20 までずれ込んでしまったという事情がある。

そんなわけで、 C++23 からなら insert_range が使えて、
これは range の条件を満たすものならなんでも受け入れられることになってる。

0797デフォルトの名無しさん2024/02/12(月) 21:37:56.53ID:WngRm50l
>>794
c2.merge(c1) ※C++17以降

0798デフォルトの名無しさん2024/02/13(火) 22:11:49.56ID:TA8E1xmn
みなさんありがとう。環境適合を優先して>>795を使うことにします。

0799デフォルトの名無しさん2024/02/18(日) 00:05:28.51ID:AtsZxBPF
コンストラクタの初期化子リストの中で、どこまで柔軟に記述できるのかなーと思ってGPT先生に聞いたら、constまたはconstexprを返す関数のみ書けるとのことでした。
コンストラクタ内部のように好きなように書けないとわかり、初期化子リストの価値が低く感じられました。

そんな制限を設けてまで初期化子リストを導入した意図は何でしょう。

0800デフォルトの名無しさん2024/02/18(日) 01:13:17.69ID:UTNyRtZE
ChatGPTなんかあてにするな、平気で間違ったこと言うんだから
constやconstexpr以外を返す関数だって普通に呼べる

試しにChatGPTに「メンバ初期化子リストではconstかconstexprを返す関数しか呼べませんが、これはなぜですか?」ってあえて間違った前提条件で質問してみたら、間違ってることに対する指摘は一切なかったし、さもこっちの質問が正しいかのようなそれっぽい返答が返ってきたし

---
俺:
C++において、コンストラクタのメンバ初期化子リスト内ではconstまたはconstexprを返す関数しか呼ぶことができません。これはなぜでしょうか?

ChatGPT:
C++において、コンストラクタのメンバ初期化子リスト内でconstまたはconstexprを返す関数しか呼ぶことができる理由は、初期化子リストがオブジェクトの初期化に使用され、実行時のコードが生成されないためです。メンバ初期化子リストはコンストラクタの一部であり、オブジェクトが生成される際に実行されます。このリスト内での関数呼び出しはコンパイル時に解決され、オブジェクトの初期化に関する情報は実行時に生成されません。

constまたはconstexprを返さない関数をメンバ初期化子リスト内で呼ぶと、実行時にコードが生成される可能性があります。しかし、これはオブジェクトが生成される前に行われる初期化の一環であり、実行時の処理としては不要なオーバーヘッドを引き起こす可能性があります。

コンストラクタのメンバ初期化子リストは、メンバ変数を適切に初期化するためのものであり、できるだけ効率的に行われるように設計されています。そのため、コンパイル時に解決されるconstまたはconstexprを返す関数の呼び出しに限定されています。
---

だからAIをあてにしちゃダメだよ

0801デフォルトの名無しさん2024/02/19(月) 00:17:49.94ID:bJlSKdBs
>>800
私が聞いたときも似たような内容が含まれていて、そうなんだねと納得してしまいました。

ではコンストラクタに書けることはすべて書けるのですね。

なおこの問いは、入門書籍にはそこまで書かれてなくて、検索でもかんたんに見つからなかったので聞きました。

0802はちみつ餃子 ◆8X2XSCHEME 2024/02/19(月) 02:33:45.03ID:j7eyydGe
>>801
たぶん >>799 で言う「初期化子リスト」は「メンバ初期化子リスト」だよね?
これらは全くの別物。
明らかに混同しやすい用語だから仕方がない部分はあるんだが、
誤った用語を元に調べたら誤った解説に当たりやすいかもしれない。

メンバ初期化子リストは直接初期化 (direct-initialization) であると規定されていて
具体的な挙動の説明は初期化の章に丸投げされている。
https://timsong-cpp.github.io/cppwp/n3337/class.base.init#7
つまりメンバ初期化子リストに特有の事情というものはない。

普通に初期化なんで、そこに違いがあるかもしれないという想像をする人がいてそういう人のために
違いが無いと断りを入れる必要があるとは入門書の著者は思わなかったんだろう。
有るものを有ると説明することはあるが無いものを無いと殊更に強調して説明はあまりしない。

0803デフォルトの名無しさん2024/02/19(月) 22:58:00.95ID:bJlSKdBs
>>802
そうですメンバ初期化子リストです。どうもありがとう。
なお書籍には、メンバ変数名(引数)やメンバ変数名(0)の例ばかりでした。

0804デフォルトの名無しさん2024/02/26(月) 09:17:00.78ID:KZUiymUx
すみません、コンストラクタの宣言/定義で A() {}; とした場合と A() = default; と
書いた場合は何が違うのでしょうか。挙動とか意味だとか...
あるいはある種のタイプクラスの場合は違いが生じるので注意とか....??

0805はちみつ餃子 ◆8X2XSCHEME 2024/02/26(月) 09:36:14.06ID:pFLZLcAJ
>>804
default を指定した場合はデフォルトのルールでコンストラクタを生成する。
生成可能な条件が満たされなかった場合でもそれ自体はエラーにはならずに
デフォルトコンストラクタは削除済と見做されるというルール。

そのときはデフォルトコンストラクタを必要とする使い方をした時点でエラーになる。

0806はちみつ餃子 ◆8X2XSCHEME 2024/02/26(月) 09:39:35.86ID:pFLZLcAJ
つまりこんなことをしてもエラーは出ないが

struct foo {
foo() = delete; // デフォルトコンストラクタを削除
};

struct bar : foo {
bar() = default; // デフォルトコンストラクタのデフォルト生成
};

int main(void) {
}

↓ こういうことをするとエラー

struct foo {
foo() = delete; // デフォルトコンストラクタを削除
};

struct bar : foo {
bar(){}
};

int main(void) {
}

0807デフォルトの名無しさん2024/03/02(土) 19:28:56.45ID:fBQwxymt
>>806
遅レスすみません。要は、コンストラクタの特定のパターンの用法をされたくない
ときに使う感じ? でそれに該当するとコンパイルエラーになるわけですよね?

自分が気になったのは、ランタイム時に何かありうるかということです
あるコードで、コンストラクタがdefault指定されているクラスが、別のクラス内
(親子関係にはない)でunique_ptrとして生成されたときに問題が生じたような
感じで....
ってもっと自分で調べてからレスしろって話ですが、現在そのコードに立ち戻る
ことができず、とりあえず疑問だけを

0808はちみつ餃子 ◆8X2XSCHEME 2024/03/02(土) 21:07:53.65ID:JOojncXx
C++ の仕様は場合分けで規則がごちゃごちゃしていることが多くて単純な一般原則として説明できない。
「要は」なんて一言でまとめられないよ。

0809デフォルトの名無しさん2024/03/03(日) 19:37:10.80ID:HNPAS3Wj
>>807
そういう目的ではないと見ていいよ
>>806が言ってるのは、基本的にはデフォルト実装でコンストラクタを作ってくれるが必ずではない、と言ってるだけ
デフォルトの(引数無しの場合、何もしない。が、基底クラスの引数無しのコンストラクタはちゃんと呼んでくれる)コンストラクタでいい場合に使う。

A() {}と書くのと基本同じだよ

0810デフォルトの名無しさん2024/03/12(火) 20:26:30.54ID:lzPsc8Dg
異なる型を含むような配列(的なもの)を作りたいのですが、可能でしょうか?
例えば template <T> struct NamedValue { string name; T value; } を定義して
NamedValue<string>{a, b} や NamedValue<int>{c, d} などの型の異なる複数の値を、
一つの配列的なものに収納したいのです
例えばvectorは全要素が同じ型じゃないと駄目ですよね

0811デフォルトの名無しさん2024/03/12(火) 21:14:27.11ID:irRbCjS4
>>810
std::tuple

0812デフォルトの名無しさん2024/03/12(火) 21:19:48.50ID:irRbCjS4
あるいは要素数がコンパイル時に決まらないなら
std::anyをコンテナに入れるとか?

0813デフォルトの名無しさん2024/03/12(火) 22:11:10.08ID:lzPsc8Dg
はい、要素数はコンパイル時に決まらないのでstd::anyのコンテナですかね
で要素を取り出すときは、どの型なのかをチェックして挙動を...

0814はちみつ餃子 ◆8X2XSCHEME 2024/03/12(火) 23:03:39.03ID:WtXn1sYk
もし >>810 の T の種類が限られているのなら std::variant を使ったほうが楽かもしれない。
std::visit を使えば型の種類ごとに処理を切り替えるのが便利なことがある。

0815デフォルトの名無しさん2024/03/23(土) 11:43:27.62ID:YZ3MX9tD
std::remove()ってファイルを消去する関数なんですね
std::move()と名前が似ているのに全然違う

0816デフォルトの名無しさん2024/03/23(土) 12:38:58.15ID:6dCwgWlj
名前空間か関数名にfileくらい入れとけって思うよね

0817デフォルトの名無しさん2024/03/23(土) 12:50:26.95ID:epZulncV
C言語以前にE言語の問題や
さすがにそのくらいの英語の勉強はしておけと思う

0818はちみつ餃子 ◆8X2XSCHEME 2024/03/23(土) 12:51:15.85ID:szITgpvT
C の規格から取り込んだものだから由来が違うんだよ。
今なら std::filesystem::remove があるからこちらを使うほうが良い作法だと思う。

0819デフォルトの名無しさん2024/03/23(土) 12:54:13.64ID:aQWBK6SI
>>815
>std::remove()ってファイルを消去する関数なんですね
std::remove()ってSTLのstd::removeじゃなく?
ちゃんとコンテナの要素をre-moveしてると思うが?

0820デフォルトの名無しさん2024/03/23(土) 13:38:01.48ID:qgcdIGgP
>>819
だよねえ??

>>815-818が何を言ってるのか分からなくて怖い

0821デフォルトの名無しさん2024/03/23(土) 13:40:27.68ID:qgcdIGgP
ああ
<cstdio>に
int remove( const char* pathname );
ってのがあるのか
https://en.cppreference.com/w/cpp/io/c/remove

0822デフォルトの名無しさん2024/03/24(日) 05:14:16.83ID:DBUI72Gl
>>818
なるほど。諸般の事情でC++14な環境で、ファイルを扱う関数を探していたら。
Boostに行く手もあるかもしれませんが、とりあえず。

0823デフォルトの名無しさん2024/03/24(日) 09:50:29.58ID:FsPOi81N
cstdio のは std:: 名前空間じゃないよね.
::remove だと思うけど

0824はちみつ餃子 ◆8X2XSCHEME 2024/03/24(日) 12:13:25.60ID:iaJ2USO3
>>823
cstdio にある関数は std 名前空間にある。
ただしグローバル名前空間「にも」あって良い。 (無くても良い。)
stdio.h の場合はグローバル名前空間で宣言されるが std 「にも」あってよい。 (無くても良い。)

0825デフォルトの名無しさん2024/04/14(日) 11:55:59.92ID:Rac57Bvn
ヒエッ……、、、ぎ、玉虫色……

0826デフォルトの名無しさん2024/04/20(土) 14:55:18.13ID:nh5GJjX6
言語そのものではないのですが、コマンドラインのデバッガやIDEでSTLのコンテナの内容を
易しく表示してくれるのってありますか?
例えばvectorなら、単純に中の要素だけを列挙してくれたりとか

ビルドにCMakeを使っているのでとりあえずCLionを使っていますが、これは
確かに変数の中身をリスト構造で見れますが、変数内の生のメンバー(M_なんちゃら等)
見えてる感じで、STLコンテナに関してはあまり親切ではないような
デバッグの際は見えた方がいい場合もあるのでしょうが。なら表示が切り替えられたりとか?
自分はmacOSですが、他のプラットフォームにしかないものも参考に聞いてみたいです

0827デフォルトの名無しさん2024/04/26(金) 10:53:44.71ID:kftlKAnq
今からC++を勉強するならC++20を基準にやっても構いませんか?

0828デフォルトの名無しさん2024/04/26(金) 10:59:40.04ID:/+TxHGye
c++20といわずc++23からやればいいのでは

0829デフォルトの名無しさん2024/04/26(金) 11:15:59.06ID:kftlKAnq
最新の規格で勉強して必要に応じて古い知識をつけていくような学び方でいいの?

0830デフォルトの名無しさん2024/04/26(金) 12:03:42.74ID:q/vvVdAs
つべこべ言わずやれ
最短コースなんてない

0831デフォルトの名無しさん2024/04/26(金) 13:37:23.03ID:+usxQk3U
C++ は基礎の上に段階的に応用が乗っかっているような綺麗な構成ではない。
全部が入り組んで捏ねまわされてグダグダや。 そんでもってクソ巨大やねん。
どこから入っても同じ。

0832デフォルトの名無しさん2024/04/27(土) 18:08:12.52ID:nxPk0zOn
質問なのですが
std::string には std::to_string(int)他の簡単文字列化関数がありますが
std::basic_string<T> に対する簡単文字列化関数はどう?

0833デフォルトの名無しさん2024/04/27(土) 21:15:22.77ID:Zg+tfmdX
>>826
WindowsのVisual Studioではできる

0834デフォルトの名無しさん2024/04/28(日) 10:47:20.65ID:xKAeYuwJ
最初に学ぶ言語がC++なら、Cより学ぶのが大変じゃん

新着レスの表示
レスを投稿する