如何初始化静态随机生成器数据成员?

huangapple go评论78阅读模式
英文:

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 &lt;random&gt;

class Random
{
private:
	static std::uniform_real_distribution&lt;float&gt; sDistribution_;
	static std::mt19937 sGenerator_;
};
// random.cpp
#include &quot;random.h&quot;

std::mt19937 Random::sGenerator_(std::random_device()); // error here
std::uniform_real_distribution&lt;float&gt; 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_deviceRandom::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&lt;float&gt; 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&lt;float&gt; 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.

huangapple
  • 本文由 发表于 2023年6月12日 03:27:58
  • 转载请务必保留本文链接:https://go.coder-hub.com/76452194.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定