Long name
ThorsAnvil::Util::getRandomIteratorFromContainer
is a really long name. I suggest something like getRandomElement
or even randomElement
.
Unnecessary function
getDist
seems kind of unnecessary to me. I think it would be cleaner to construct the distribution directly.
std::uniform_int_distruction<int> dist{0, container.size() - 1};
Types
The integer type used for iterator arithmetic is typename C::difference_type
. This is almost always equivalent to std::ptrdiff_t
so to be crystal clear, use std::ptrdiff_t
.
std::uniform_int_distruction<std::ptrdiff_t> dist{0, container.size() - 1};
Unnecessary variable
offset
is initialized with a random offset and is only used once. If it's only used once then it doesn't really need to exist.
std::advance(pos, dist(generator));
Wrong function
std::advance
modifies an existing iterator. This means that we need store the iterator, advance it, then return the iterator. That's three steps. std::next
takes an iterator and returns an incremented one.
return std::next(container.begin(), dist(generator));
Covering all cases
Using .begin()
and .size()
is a little bit restrictive. If we use std::begin
and std::size
, this function will work on C-style arrays which is a nice. If we want to be even more general (as Toby mentioned in the comments), we can let ADL pick up the right function for containers that declare their own begin
and size
functions.
using std::begin;
using std::size;
Short names
My answer has been pretty nitpicky so far but this is particularly nitpicky. Long template parameter names that clearly describe the parameter are better than single character names.
template <typename Container, typename Generator>
How I would write it
After applying the above transformations. We get this function:
template <typename Container, typename Generator>
auto random_element(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));
}
namesapce
Did you test your code? ;) \$\endgroup\$#include
lines, rather than us all having to figure out what's required. And I'd expect#include <iterator>
in there, as it's impossible to instantiate the template without needing a definition ofstd::advance
, even though it can be parsed without. \$\endgroup\$