I lie about being a random player - doesn’t it?

I wrote a RandIt class (code below) that acts like an iterator, but returns random integers when dereferenced. The main use case is to initialize a vector with random data, as in

std::vector<int> v(RandIt<0,99>{}, RandIt<0,99>{50}); 

to generate 50 numbers between 0 and 99.

typedef RandIt::iterator_category - std::random_access_iterator_tag because

  • it must be at least ForwardIterator for the vector constructor in order to allocate the right amount of space for the assembly using std::distance . Otherwise, emplace_back used, with redistribution and copying.
  • it should be RandomAccessIterator for std::distance for constant time, instead of incrementing and testing in a loop.

However, this is a lie, since RandIt dereferencing returns an int value by value, and ForwardIterators are best needed to return a reference to an object in memory.

(This could also be a lie due to the rejection of the ForwardIterator multi-pass guarantee: repeating the sequence will again give different results. But cppreference gives a “formal” version

expression (void)++It(a), *a equivalent to *a

which seems to be true for certain "equivalent" values.)

So I definitely break the rules by saying that I'm not like that. However, this seems to work.

Does it bite me? What are the potential consequences of lying about it?


 #include <random> #include <iterator> template <int min, int max> struct RandIt { typedef int difference_type; typedef int value_type; typedef const int* pointer; typedef const int& reference; typedef std::random_access_iterator_tag iterator_category; // this is a lie static std::knuth_b rng; static std::uniform_int_distribution<int> idist; int i; explicit RandIt(int i = 0) : i{i} {} int operator*() const {return idist(rng);} int operator[](int) const {return idist(rng);} RandIt& operator++() {++i; return *this;} RandIt operator++(int) {return RandIt{i++};} RandIt& operator--() {--i; return *this;} RandIt operator--(int) {return RandIt{i--};} RandIt& operator+=(int k) {i += k; return *this;} RandIt& operator-=(int k) {i -= k; return *this;} RandIt operator+ (int k) const {return RandIt{i+k};} RandIt operator- (int k) const {return RandIt{ik};} friend RandIt operator+(int k, RandIt a) {return RandIt{k + ai};} friend int operator- (RandIt a, RandIt b) {return ai - bi;} friend bool operator==(RandIt a, RandIt b) {return ai == bi;} friend bool operator!=(RandIt a, RandIt b) {return ai != bi;} friend bool operator<=(RandIt a, RandIt b) {return ai <= bi;} friend bool operator< (RandIt a, RandIt b) {return ai < bi;} friend bool operator>=(RandIt a, RandIt b) {return ai >= bi;} friend bool operator> (RandIt a, RandIt b) {return ai > bi;} }; template <int min, int max> std::knuth_b RandIt<min, max>::rng{std::random_device{}()}; // On some platforms (mingw), random_device is deterministic, so rng // will always produce the same values. template <int min, int max> std::uniform_int_distribution<int> RandIt<min, max>::idist{min, max}; 

Take a look at Coliru .

+6
source share

All Articles