Skip to main content
Spelling and grammar; expand initialism
Source Link
Toby Speight
  • 81.7k
  • 14
  • 101
  • 308

I think you should clarify what you want. Depending on that, the anwseranswer will be slightly different.

DoIf you want an iterator to a random element than @Kerndogsthen Kerndog's answer is really close:

template <typename Container, typename Generator>
auto random_iterator(Container &con, Generator &gen) {
  using std::begin;
  using std::size;
  std::uniform_int_distribution<std::ptrdiff_t> dist{0, size(con) - 1};
  return std::next(begin(con), dist(gen));
}

template <typename Container, typename Generator>
auto random_iterator(const Container &con, Generator &gen) {
  using std::cbegin;
  using std::size;
  std::uniform_int_distribution<std::ptrdiff_t> dist{0, size(con) - 1};
  return std::next(cbegin(con), dist(gen));
}

NotNote that there should be a const/non-const overload.

If you only want the element from the container you should retrieve it or get a reference?

template <typename Container, typename Generator>
auto random_reference(const Container &con, Generator &gen) {
  using std::size;
  std::uniform_int_distribution<std::size_t> dist{0, size(con) - 1};
  return con[dist(gen)];
}

Which standard do you use? If C++20 is possible then you should use at least the range concept and ranges:ranges::size:size

template <range Container, typename Generator>
auto random_const_iterator(const Container &con, Generator &gen) {
  std::uniform_int_distribution<std::ptrdiff_t> dist{0, std::ranges::size(con) - 1};
  return std::next(std::ranges::cbegin(con), dist(gen));
}

Note that std::ranges::size/std::ranges::cbegin are CPOscustomization point objects (CPOs), so you should call them qualified andqualified; you do not need to use ADL as that is already inside the mechanics of the CPO.

I think you should clarify what you want. Depending on that the anwser will be slightly different.

Do you want an iterator to a random element than @Kerndogs answer is really close:

template <typename Container, typename Generator>
auto random_iterator(Container &con, Generator &gen) {
  using std::begin;
  using std::size;
  std::uniform_int_distribution<std::ptrdiff_t> dist{0, size(con) - 1};
  return std::next(begin(con), dist(gen));
}

template <typename Container, typename Generator>
auto random_iterator(const Container &con, Generator &gen) {
  using std::cbegin;
  using std::size;
  std::uniform_int_distribution<std::ptrdiff_t> dist{0, size(con) - 1};
  return std::next(cbegin(con), dist(gen));
}

Not that there should be a const/non-const overload

If you only want the element from the container you should retrieve it or get a reference

template <typename Container, typename Generator>
auto random_reference(const Container &con, Generator &gen) {
  using std::size;
  std::uniform_int_distribution<std::size_t> dist{0, size(con) - 1};
  return con[dist(gen)];
}

Which standard do you use? If C++20 is possible then you should use at least the range concept and ranges::size

template <range Container, typename Generator>
auto random_const_iterator(const Container &con, Generator &gen) {
  std::uniform_int_distribution<std::ptrdiff_t> dist{0, std::ranges::size(con) - 1};
  return std::next(std::ranges::cbegin(con), dist(gen));
}

Note that std::ranges::size/std::ranges::cbegin are CPOs so you should call them qualified and do not need to use ADL as that is already inside the mechanics of the CPO

I think you should clarify what you want. Depending on that, the answer will be slightly different.

If you want an iterator to a random element then Kerndog's answer is really close:

template <typename Container, typename Generator>
auto random_iterator(Container &con, Generator &gen) {
  using std::begin;
  using std::size;
  std::uniform_int_distribution<std::ptrdiff_t> dist{0, size(con) - 1};
  return std::next(begin(con), dist(gen));
}

template <typename Container, typename Generator>
auto random_iterator(const Container &con, Generator &gen) {
  using std::cbegin;
  using std::size;
  std::uniform_int_distribution<std::ptrdiff_t> dist{0, size(con) - 1};
  return std::next(cbegin(con), dist(gen));
}

Note that there should be a const/non-const overload.

If you only want the element from the container you should retrieve it or get a reference?

template <typename Container, typename Generator>
auto random_reference(const Container &con, Generator &gen) {
  using std::size;
  std::uniform_int_distribution<std::size_t> dist{0, size(con) - 1};
  return con[dist(gen)];
}

Which standard do you use? If C++20 is possible then you should use at least the range concept and ranges::size:

template <range Container, typename Generator>
auto random_const_iterator(const Container &con, Generator &gen) {
  std::uniform_int_distribution<std::ptrdiff_t> dist{0, std::ranges::size(con) - 1};
  return std::next(std::ranges::cbegin(con), dist(gen));
}

Note that std::ranges::size/std::ranges::cbegin are customization point objects (CPOs), so you should call them qualified; you do not need to use ADL as that is already inside the mechanics of the CPO.

Source Link
miscco
  • 4.3k
  • 11
  • 17

I think you should clarify what you want. Depending on that the anwser will be slightly different.

Do you want an iterator to a random element than @Kerndogs answer is really close:

template <typename Container, typename Generator>
auto random_iterator(Container &con, Generator &gen) {
  using std::begin;
  using std::size;
  std::uniform_int_distribution<std::ptrdiff_t> dist{0, size(con) - 1};
  return std::next(begin(con), dist(gen));
}

template <typename Container, typename Generator>
auto random_iterator(const Container &con, Generator &gen) {
  using std::cbegin;
  using std::size;
  std::uniform_int_distribution<std::ptrdiff_t> dist{0, size(con) - 1};
  return std::next(cbegin(con), dist(gen));
}

Not that there should be a const/non-const overload

If you only want the element from the container you should retrieve it or get a reference

template <typename Container, typename Generator>
auto random_reference(const Container &con, Generator &gen) {
  using std::size;
  std::uniform_int_distribution<std::size_t> dist{0, size(con) - 1};
  return con[dist(gen)];
}

Which standard do you use? If C++20 is possible then you should use at least the range concept and ranges::size

template <range Container, typename Generator>
auto random_const_iterator(const Container &con, Generator &gen) {
  std::uniform_int_distribution<std::ptrdiff_t> dist{0, std::ranges::size(con) - 1};
  return std::next(std::ranges::cbegin(con), dist(gen));
}

Note that std::ranges::size/std::ranges::cbegin are CPOs so you should call them qualified and do not need to use ADL as that is already inside the mechanics of the CPO