最終更新日時(UTC):
が更新

履歴 編集

function template
<random>

std::generate_random(C++26)

namespace std::ranges {
  template <class R, class G>
    requires output_range<R, invoke_result_t<G&>> &&
             uniform_random_bit_generator<remove_cvref_t<G>>
  constexpr borrowed_iterator_t<R>
    generate_random(R&& r, G&& g);                  // (1) C++26

  template <class G,
            output_iterator<invoke_result_t<G&>> O,
            sentinel_for<O> S>
    requires uniform_random_bit_generator<remove_cvref_t<G>>
  constexpr O
    generate_random(O first, S last, G&& g);        // (2) C++26

  template <class R, class G, class D>
    requires output_range<R, invoke_result_t<D&, G&>> &&
             invocable<D&, G&> &&
             uniform_random_bit_generator<remove_cvref_t<G>>
  constexpr borrowed_iterator_t<R>
    generate_random(R&& r, G&& g, D&& d);           // (3) C++26

  template <class G,
            class D,
            output_iterator<invoke_result_t<D&, G&>> O,
            sentinel_for<O> S>
    requires invocable<D&, G&> &&
             uniform_random_bit_generator<remove_cvref_t<G>>
  constexpr O
    generate_random(O first, S last, G&& g, D&& d); // (4) C++26
}

概要

乱数列を生成する。

  • (1) : 出力範囲rの各要素に、乱数生成器gで生成した乱数を代入する
  • (2) : 出力イテレータ範囲[first, last)の各要素に、乱数生成器gで生成した乱数を代入する
  • (3) : 出力範囲rの各要素に、乱数生成器gと分布生成器dで生成した乱数を代入する
  • (4) : 出力イテレータ範囲[first, last)の各要素に、乱数生成器gと分布生成器dで生成した乱数を代入する

この関数は、for文を使用した以下のコードをアルゴリズム関数化したものである。

std::vector<int> v(10);
std::mt19937 gen {std::random_device{}()};
std::uniform_int_distribution<int> dist{1, 100};

// 以下の3つのコードは等価
std::ranges::generate_random(v, gen);                  // (1)
std::ranges::generate_random(v.begin(), v.end(), gen); // (2)
for (auto& x : v) {
  x = gen();
}

// 以下の3つのコードは等価
std::ranges::generate_random(v, gen, dist);                  // (3)
std::ranges::generate_random(v.begin(), v.end(), gen, dist); // (4)
for (auto& x : v) {
  x = dist(gen);
}

効果

  • (1) :

    • g.generate_random(std::forward<R>(r))が妥当な式であれば、それを呼び出す
      • 備考 : 乱数生成器がgenerate_random()メンバ関数をもっていればそれを使用する
    • そうでなく、Rsized_rangeのモデルである場合、値Nspan<invoke_result_t<G&>, N>型オブジェクトsに対して、式g()またはg.generate_random(s)未規定の回数だけ呼び出して実行し、rの各要素に代入する
      • 備考 : ここでのNは乱数生成の回数と異なってもよい
    • そうでなければ、ranges::generate(std::forward<R>(r), ref(g))を呼び出す
      • 備考 : std::forward_listのようなsize()メンバ関数をもたないコンテナがこちらに該当する
  • (2) : 以下と等価

    return generate_random(subrange<O, S>(std::move(first), last), g);
    

  • (3) :

    • d.generate_random(std::forward<R>(r), g)が妥当な式であれば、それを呼び出す
      • 備考 : 分布生成器がgenerate_random()メンバ関数をもっていればそれを使用する
    • そうでなく、Rsized_rangeのモデルである場合、値Nspan<invoke_result_t<D&, G&>, N>型オブジェクトsに対して、式invoke(d, g)またはd.generate_random(s, g)未規定の回数だけ呼び出して実行し、rの各要素に代入する
      • 備考 : ここでのNは乱数生成の回数と異なってもよい
    • そうでなければ、ranges::generate(std::forward<R>(r), [&d, &g] { return invoke(d, g); })を呼び出す
      • 備考 : std::forward_listのようなsize()メンバ関数をもたないコンテナがこちらに該当する
  • (4) : 以下と等価

    return generate_random(subrange<O, S>(std::move(first), last), g, d);
    

戻り値

#include <random>
#include <print>
#include <vector>

int main()
{
  std::random_device seed_gen;
  std::mt19937 engine(seed_gen());
  std::uniform_int_distribution<int> dist{0, 100};

  std::vector<int> v(10);

  // コンテナの全要素を乱数で埋める
  std::ranges::generate_random(v, engine);
  std::println("{}", v);

  // コンテナの全要素を、指定した分布の乱数で埋める
  std::ranges::generate_random(v, engine, dist);
  std::println("{}", v);
}

出力例

[2034091041, 1919373608, 514210727, -1154669807, -315048337, -1224623446, -1986406128, -1034429876, -844125616, 1858136340]
[83, 25, 48, 15, 9, 60, 47, 31, 91, 54]

バージョン

言語

  • C++26

処理系

参照