[英]How to create std::initializer_list with integer_sequence?
[英]How to create a std::initializer_list from variable data
我正在尝试使用传递给类构造函数的数据创建一个std::discrete_distribution
对象。 我知道如何使用静态数据创建它,但无法弄清楚如何使用可变数据(干净利落)。 我现在所拥有的“有效”,但却很痛苦。 有没有更合适的方法呢?
distInit = { distArray[0], ... };
线是问题。
#include <iostream>
#include <iomanip>
#include <initializer_list>
#include <map>
#include <random>
class Die {
private:
int loadSide;
double loadAmount;
std::mt19937 generator;
std::discrete_distribution<> distribution;
std::initializer_list<double> distInit;
std::array<double, 7> distArray;
public:
Die( int loadSide, double loadAmount ) : loadSide(loadSide), loadAmount(loadAmount) {
distArray.fill( 1 );
distArray[0] = 0;
distArray[this->loadSide] = this->loadAmount;
distInit = { distArray[0], distArray[1], distArray[2], distArray[3], distArray[4], distArray[5], distArray[6] };
distribution.param( distInit );
};
int roll( ) {
return distribution( generator );
};
};
const int ROUNDS = 10000;
int main() {
Die* die = new Die( 5, 20 );
std::map<int, int> m;
for(int n=0; n < ROUNDS; n++) {
m[die->roll()]++;
}
for(auto p : m) {
std::cout << p.first << " generated " << std::setiosflags(std::ios::fixed) << std::setprecision(2) << (float) p.second / ROUNDS << " times\n";
}
}
我可能不会问正确的问题,如果是的话,我会提前道歉。 这是一个很大的可能性,因为我很惊讶我无法在这个主题上找到任何(显然)相关的点击。
我的编译器是g++-mp-4.8 (MacPorts gcc48 4.8-20130411_0) 4.8.1 20130411 (prerelease)
命令行/opt/local/bin/g++-mp-4.8 -std=c++11 test.cpp -o test
如果你有可变数据,你应该使用discrete_distribution
构造函数来获取一对迭代器 :
template< class InputIt >
discrete_distribution( InputIt first, InputIt last );
你不应该试图直接构造param_type
; 而是使用辅助函数来构建您的分布:
class Die {
private:
std::mt19937 generator;
std::discrete_distribution<> distribution;
static std::discrete_distribution<> makeDistribution(
int loadSide, double loadAmount )
{
std::array<double, 7> distArray;
distArray.fill( 1 );
distArray[0] = 0;
distArray[loadSide] = loadAmount;
return {std::begin(distArray), std::end(distArray)};
}
public:
Die( int loadSide, double loadAmount ) :
generator{ },
distribution{ makeDistribution( loadSide, loadAmount ) }
{}
int roll( ) {
return distribution( generator );
}
};
std::initializer_list
仅用作临时对象(函数参数)或局部变量。 它不是一个容器,它没有任何东西; 它是匿名临时数组的访问者。
该标准包括一个类似于您的代码的示例,§8.5.4/ 6,提及
initializer_list对象在构造函数的ctor-initializer中初始化,因此数组只会持续存在直到构造函数退出,因此在构造函数退出后对i4元素的任何使用都会产生未定义的行为。
在你的情况下,它是构造函数的主体,而不是正文之前的ctor-initializer,但故事是相同的。 你的程序现在正在运作,这真是太笨了。
要将分布存储在对象中,请使用std::array
或std::vector
。 array
更有效但它不支持arr = { … }
语法。 (有一些简单的替代方案。) vector
使用大括号和=
运算符支持你的语法; 此支持使用隐式std::initializer_list
。
我不知道有什么更好的方法可以从像std::array
这样的容器创建一个std::initializer_list
,而不是OP中显示的那个。
但是,对于原始问题,即将参数传递给分布,我可以建议更简单的东西。
typedef std::discrete_distribution<>::param_type param_type;
distribution.param(param_type(distArray.begin(), distArray.end()));
该标准说分发必须提供一个类型成员param_type
(这是param()
采用的param()
类型)但不指定它。 但是,[rand.req.dist]说
对于D [分布类型]的每个构造函数,其参数对应于分布的参数,P [param_type]应具有相应的构造函数,这些构造函数具有相同的要求并且在数量,类型和默认值方面具有相同的参数。
好吧,事实证明, std::discrete_distribution<>
有一个构造函数,它将迭代器指向参数范围。 因此,无论std::discrete_distribution<>::param_type
是什么,它都必须具有类似的构造函数。 因此,我建议从distArray.begin()
和distArray.end()
创建一个param_type
,并将其传递给distribution.param()
。
旁注:您不再需要std::initializer_list<double> distInit;
在你的班上 在我看来,你不需要std::array<double, 7> distArray
作为类成员(它可能是Die
的构造函数中的局部变量)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.