英文:
How do I initialize a static random generator data member?
问题
// 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);
在编译时出现错误时,可以尝试将 std::random_device()
的括号添加到后面,如上所示。
英文:
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?
答案1
得分: 5
std::mt19937 Random::sGenerator_(std::random_device());
是最令人困扰的解析的一个实例。
您希望执行直接初始化,但实际上您正在:
> 声明Random::sGenerator_
为一个函数,该函数接受一个指向不带参数的函数的指针,并返回std::random_device
。Random::sGenerator_
函数返回std::mt19937
。
这是编译器的看法,与Random::sGenerator_
的原始定义相冲突,该定义将其声明为类型为std::mt19937
的静态数据成员。
解决方案非常简单:std::random_device
是一种类型,而不是函数,因此您需要在调用它之前进行初始化,如下所示:
std::mt19937 Random::sGenerator_{std::random_device{}()};
// 或者
std::mt19937 Random::sGenerator_{std::random_device()()};
// 或者
std::mt19937 Random::sGenerator_(std::random_device{}());
通常,一些人认为更喜欢列表初始化是一个好习惯,因为它避免了这种解析模糊性。只需注意,当一个类型具有接受std::initializer_list
的构造函数时,它的工作方式会有所不同(对于我们使用的任何类型都不是问题)。
自C++17以来
您还可以在类中初始化静态数据成员,如下所示:
class Random
{
private:
static inline std::uniform_real_distribution<float> sDistribution_{0, 1};
static inline std::mt19937 sGenerator_{std::random_device{}()};
};
注意:如果您的类的所有操作都是存储静态数据成员,那么它很可能只应该是一个namespace
,而不是一个class
。
<details>
<summary>英文:</summary>
```cpp
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 returning std::random_device
. The Random::sGenerator_
function returns std::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).
Since C++17
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
.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论