'generate' is not a member of 'std::random_device' inside window's <random> header file

Viewed 705

So this application is giving me a compilation error inside random and I tried everything to fix it short of formatting my hard drive and reinstalling windows.

First time in a long time working with C++ (usually a .net guy) so I figured you lovely people might have an answer to this.

Code in question (remember, this is inside random)

// CLASS TEMPLATE mersenne_twister_engine
template <class _Ty, size_t _Wx, size_t _Nx, size_t _Mx, size_t _Rx, _Ty _Px, size_t _Ux, _Ty _Dx, size_t _Sx, _Ty _Bx,
    size_t _Tx, _Ty _Cx, size_t _Lx, _Ty _Fx>
class mersenne_twister_engine : public mersenne_twister<_Ty, _Wx, _Nx, _Mx, _Rx, _Px, _Ux, _Sx, _Bx, _Tx, _Cx, _Lx> {
public:
    static constexpr unsigned long long _Max = (((1ULL << (_Wx - 1)) - 1) << 1) + 1;

    _RNG_REQUIRE_UINTTYPE(mersenne_twister_engine, _Ty);

    static_assert(0 < _Mx && _Mx <= _Nx && 2U < _Wx && _Rx <= _Wx && _Ux <= _Wx && _Sx <= _Wx && _Tx <= _Wx
                      && _Lx <= _Wx && _Wx <= numeric_limits<_Ty>::digits && _Px <= _Max && _Bx <= _Max && _Cx <= _Max
                      && _Dx <= _Max && _Fx <= _Max,
        "invalid template argument for mersenne_twister_engine");

    using _Mybase     = mersenne_twister<_Ty, _Wx, _Nx, _Mx, _Rx, _Px, _Ux, _Sx, _Bx, _Tx, _Cx, _Lx>;
    using result_type = _Ty;

    static constexpr size_t word_size              = _Wx;
    static constexpr size_t state_size             = _Nx;
    static constexpr size_t shift_size             = _Mx;
    static constexpr size_t mask_bits              = _Rx;
    static constexpr _Ty xor_mask                  = _Px;
    static constexpr size_t tempering_u            = _Ux;
    static constexpr _Ty tempering_d               = _Dx;
    static constexpr size_t tempering_s            = _Sx;
    static constexpr _Ty tempering_b               = _Bx;
    static constexpr size_t tempering_t            = _Tx;
    static constexpr _Ty tempering_c               = _Cx;
    static constexpr size_t tempering_l            = _Lx;
    static constexpr _Ty initialization_multiplier = _Fx;

    static constexpr result_type default_seed = 5489U;

    explicit mersenne_twister_engine(result_type _X0 = default_seed) : _Mybase(_X0, _Dx, _Fx) {}

    template <class _Seed_seq, _Enable_if_seed_seq_t<_Seed_seq, mersenne_twister_engine> = 0>
    explicit mersenne_twister_engine(_Seed_seq& _Seq) : _Mybase(default_seed, _Dx, _Fx) {
        seed(_Seq);
    }

    void seed(result_type _X0 = default_seed) { // set initial values from specified value
        _Mybase::seed(_X0, _Fx);
    }

    template <class _Seed_seq, _Enable_if_seed_seq_t<_Seed_seq, mersenne_twister_engine> = 0>
    void seed(_Seed_seq& _Seq) { // reset sequence from seed sequence
        constexpr int _Kx = (_Wx + 31) / 32;
        unsigned long _Arr[_Kx * _Nx];
        _Seq.generate(&_Arr[0], &_Arr[_Kx * _Nx]);

        int _Idx0 = 0;
        _Ty _Sum  = 0;
        for (size_t _Ix = 0; _Ix < _Nx; ++_Ix, _Idx0 += _Kx) { // pack _Kx words
            this->_Ax[_Ix] = _Arr[_Idx0];
            for (int _Jx = 0; ++_Jx < _Kx;) {
                this->_Ax[_Ix] |= static_cast<_Ty>(_Arr[_Idx0 + _Jx]) << (32 * _Jx);
            }

            this->_Ax[_Ix] &= this->_WMSK;

            if (_Ix == 0) {
                _Sum = this->_Ax[_Ix] >> _Rx;
            } else {
                _Sum |= this->_Ax[_Ix];
            }
        }

        if (_Sum == 0) {
            this->_Ax[0] = this->_WMSK;
        }

        this->_Idx = _Nx;
    }

    _NODISCARD static constexpr result_type(min)() {
        return 0;
    }

    _NODISCARD static constexpr result_type(max)() {
        return _Mybase::_WMSK;
    }
};

The line in question:

_Seq.generate(&_Arr[0], &_Arr[_Kx * _Nx]);

How random is being used:


std::mt19937 seed;
std::uniform_int_distribution<int> dist;

void SetLargeRand() // OK
{
    seed = std::mt19937(std::random_device());
    dist = std::uniform_int_distribution<int>(0,2147483647);
}

long GetLargeRand() // OK
{
    return dist(seed);
}

Thank you so much.

2 Answers

Minimal code that produces error from title

#include<random>
int random_function()
{
    std::uniform_int_distribution<int> dist(0,10);
    static std::random_device rd;
    static auto mt = std::mt19937(rd);
//                                ^ Error here
    return dist(mt);
}


#include<iostream>
int main(){
    std::cout<<random_function()<<std::endl;
    return 0;
}

Minimal code that fixes error

#include<random>
int random_function()
{
    std::uniform_int_distribution<int> dist(0,10);
    static std::random_device rd;
    static auto mt = std::mt19937(rd());
//                                  ^ Fix here
    return dist(mt);
}
    

#include<iostream>
int main(){
    std::cout<<random_function()<<std::endl;
    return 0;
}

So in the context of the OP's code,

    seed = std::mt19937(std::random_device());

should be changed to

    seed = std::mt19937(std::random_device()());

This is because random_device is a functor that returns what mt19937 wants. Constructing one isn't enough, calling it is what is required. Thus this constructs, calls, and destructs; the random_device functor, all in one go.

I assume you want overload number 3 from this std::mt19937 reference?

You're not supposed to pass a std::random_device object there (in fact, you're using a non-portable Visual Studio extension that allows you to pass temporary objects as non-const references) but a reference to an object that can generate a random value.

You either have to come up with your own that follows the SeedSequence requirements, or use the standard std::seed_seq class.

Or, better yet, rely on the standard seed which will be more than adequate for almost all situations.

So you don't really need the SetLargeRand function at all, just the definitions:

std::mt19937 seed;
std::uniform_int_distribution<int> dist(0,2147483647);
Related