I have Random
class, and I don`t know how correctly initialize its static data members.
// random.h
#pragma once
#include <random>
class Random
{
private:
static std::uniform_real_distribution<float> sDistribution_;
static std::mt19937 sGenerator_;
};
// random.cpp
#include "random.h"
std::mt19937 Random::sGenerator_(std::random_device()); // error here
std::uniform_real_distribution<float> Random::sDistribution_(0.0f, 1.0f);
When I compile this, I get an error:
declaration is not compatible with
std::mt19937
.
How do I correctly initialize this member?
std::mt19937 Random::sGenerator_(std::random_device());
is an instance of the most vexing parse. You wanted to perform direct initialization, but you're actually:
declaring
Random::sGenerator_
as a function taking a pointer to a function taking no parameters, and returningstd::random_device
. TheRandom::sGenerator_
function returnsstd::mt19937
.
This is what the compiler thinks, and it conflicts with the original definition of Random::sGenerator_
, which declares it as a static data member of type std::mt19937
.
The solution is very simple: std::random_device
is a type, not a function, so you need to initialize it before calling it, like:
std::mt19937 Random::sGenerator_{std::random_device{}()};
// or
std::mt19937 Random::sGenerator_{std::random_device()()};
// or
std::mt19937 Random::sGenerator_(std::random_device{}());
In general, preferring list initialization is considered good practice by some, because it avoids this parsing ambiguity. Just be aware that it works differently when a type has a constructor taking std::initializer_list
(not a problem for any of the types we're using).
You can also initialize the static data member in the class, like:
class Random
{
private:
static inline std::uniform_real_distribution<float> sDistribution_{0, 1};
static inline std::mt19937 sGenerator_{std::random_device{}()};
};
Note: if all your class does is storing static data members, it should likely just be a namespace
, not a class
.