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

3
我有一个Random类,但我不知道如何正确初始化它的静态数据成员。
// 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::mt19937 不兼容。

我该如何正确初始化这个成员?


你确定要这样做吗?为什么不将它们作为常规属性,并将类本身作为单例,甚至更好的是线程本地化? - tadman
你确定你想这样做吗?为什么不将它们作为常规属性,并将类本身作为单例,甚至更好的是线程本地化? - undefined
查找有关 std::random_device 的文档,示例在那里。 - Pepijn Kramer
查找有关 std::random_device 的文档,示例就在那里。 - undefined
1
std::random_device()更改为std::random_device{}()random_device不是一个函数,而是一个类,所以你需要先创建一个实例,然后再调用它。 - Ted Lyngmo
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{}()};
// or
std::mt19937 Random::sGenerator_{std::random_device()()};
// or
std::mt19937 Random::sGenerator_(std::random_device{}());

一般来说,有些人认为更喜欢使用列表初始化(list initialization)是一个好的做法,因为它避免了解析的歧义。只要注意当类型具有接受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{}()};
};

注意:如果你的类只是存储静态数据成员,那么它很可能应该是一个命名空间而不是一个类。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接