質問: `std::mt_19937`クラスを`std::random_device`クラスの乱数で初期化する時このコードはコンパイルエラーになります。 ``` #include #include int main(){ std::mt19937 gen(std::random_device()()); std::cout << gen() << std::endl; return 0; } ``` `std::random_dvice()`が関数として捉えられているようです。(もしくは関数宣言?) なので `std::mt19937 gen((std::random_device())());` とデフォルトコンストラクタを呼んでいることを明示化してやるとコンパイルが通ります。 これだとカッコの多さが気になるので `std::mt19937 gen(std::random_deviece{}())` と一様初期化で一時オブジェクトを生成するとうまくできるのですが このカッコを多数書く書き方や一様初期化でやることが普通なのでしょうか?
回答: [c](/questions/tagged/c "'c' のタグが付いた質問を表示") との互換性確保のため ``` void func() { myclass t(); } ``` と書いたなら、これは `t()` が関数であることの局所宣言 (`t` の返却値は `myclass` 引数はナシ) であると読む仕様です ([c++98](/questions/tagged/c%2b%2b98 "'c++98' のタグが付いた質問を表示") より一貫してこの仕様) これがわかりにくい、ないしは直感的でないということで [c++11](/questions/tagged/c%2b%2b11 "'c++11' のタグが付いた質問を表示") で `uniform initialization` 一様初期化という仕様が追加されています。 提示例の場合 `std::random_device` の関数オブジェクトを一時オブジェクトとして生成し、その関数オブジェクトを引数ナシで呼びたいわけです。なので [c++11](/questions/tagged/c%2b%2b11 "'c++11' のタグが付いた質問を表示") より古い場合 `(functype())()` [関数宣言にならない記述方式] [c++11](/questions/tagged/c%2b%2b11 "'c++11' のタグが付いた質問を表示") 以後ならば、 `functype{}()` または同上 [一様初期化は関数宣言と読まない仕様] のどちらかの記述方法になるのは言語仕様書通りということになりそうです。普通か否かというレベルでなくて、こう書かざるを得ないってことで。 `std::random_device` 自体が [c++11](/questions/tagged/c%2b%2b11 "'c++11' のタグが付いた質問を表示") で追加されている機能なので一様初期化を使うことにためらう必要は一切なく ``` std::mt19937 gen{std::random_device{}()}; ``` と書いちゃうほうがわかりやすくて一般的だと思います。一様初期化を知っている読者にとっては 関数呼び出しに `{ }` は使えないこと コンストラクタ呼び出しに `{ }` が使えることは既知であるので、途中の `( )` が関数呼び出しであることが半自明で読みやすいと個人的に判断します。 いついかなるときも一様初期化に書き換えてよいかというとそんなことはなくて ``` std::vector v(10); std::vector w{10}; ``` は全く違う意味になるので要注意。