Closed. This question is
off-topic。它当前不接受答案。
想改善这个问题吗?
Update the question,所以它是
on-topic,用于堆栈溢出。
去年关闭。
我正在使用Visual Studio 2017 CE版本15.6.2,并将编译器语言选项设置为:
ISO C++ Latest Draft Standard (/std:c++latest)
我正在使用
<random>
中的大多数功能,并且有2个非模板类,即
RandomEngine
和
RandomDistribution
。
无法删除这些类,因为它们已删除默认构造函数。所有方法在类中都是静态的。
在
RandomEngine
类中,我的静态方法是根据标准库中的某些随机引擎(例如
std::mt19937
)命名的。它支持通过传递给静态函数的枚举类型和所需的其他参数,通过不同的机制为引擎提供种子的功能。这些引擎中的任何一种都有4种播种方式:{
CHRONO_CLOCK
,
SEED_VALUE
,
SEED_SEQ
,
RANDOM_DEVICE
}。有一个具有通用名称
getEngine(...)
的函数模板,使用专门化功能,我能够创建此函数,以返回每种不同类型的引擎。该课程太大了,但我将展示一些示例:
随机生成器
#ifndef RANDOM_GENERATOR_H
#define RANDOM_GENERATOR_H
#include <limits>
#include <chrono>
#include <random>
#include <type_traits>
class RandomEngine {
public:
enum SeedType { USE_CHRONO_CLOCK, USE_RANDOM_DEVICE, USE_SEED_VALUE, USE_SEED_SEQ };
using Clock = std::conditional_t<std::chrono::high_resolution_clock::is_steady,
std::chrono::high_resolution_clock,
std::chrono::steady_clock>;
RandomEngine() = delete;
protected:
static std::random_device& getRandomDevice() {
static std::random_device device{};
return device;
}
static std::size_t getTimeNow() {
std::size_t now = static_cast<std::size_t>( Clock::now().time_since_epoch().count() );
return now;
}
static std::seed_seq& getSeedSeq( std::initializer_list<std::size_t>& list ) {
static std::seed_seq seq( list );
return seq;
}
public:
// I'll just show two to keep the list short; but they all follow the same pattern.
static std::default_random_engine& getDefaultRandomEngine( SeedType type, std::size_t seedVal, std::initializer_list<std::size_t> list ) {
static std::default_random_engine engine{};
switch( type ) {
case USE_CHRONO_CLOCK: { engine.seed( getTimeNow() ); break; }
case USE_SEED_VALUE: { engine.seed( seedVal ); break; }
case USE_SEED_SEQ: { engine.seed( getSeedSeq( list ) ); break; }
default:{engine.seed( getRandomDevice()() ); break; }
}
return engine;
}
static std::mt19937& getMt19937( SeedType type, std::size_t seedValue, std::initializer_list<std::size_t> list ) {
static std::mt19937 engine{};
switch( type ) {
case USE_CHRONO_CLOCK: { engine.seed( getTimeNow() ); break; }
case USE_SEED_VALUE: { engine.seed( seedValue ); break; }
case USE_SEED_SEQ: { engine.seed( getSeedSeq( list ) ); break; }
default: { engine.seed( getRandomDevice()() ); break; }
}
return engine;
}
// After the rest of the engine types about 8-10 more...
// I have this function template within the above class.
template<class Engine>
static Engine& getEngine( RandomEngine::SeedType seedType, std::size_t seedValue, std::initializer_list list ) {
return getDefaultRandomEngine( seedType, seedValue, list );
}
};
// ... other class here but will get to that in a bit.
class RandomDistribution { ... };
typedef RandomEngine RE;
typedef RandomDistribution RD;
// function template here which I will get to in a bit.
#endif // !RANDOM_GENERATOR_H
然后在我的RandomGenerator.cpp文件中,将
RandomEngine::getEngine(...)
函数专门化为:
RandomGenerator.cpp
#include "RandomGenerator.h"
// specializations of different engines
template<>
static std::knuth_b& RandomEngine::getEngine( SeedType seedType, std::size_t seedValue, std::initializer_list<std::size_t> list ) {
return getKnuthB( seedType, seedValue, list );
}
template<>
static std::minstd_rand0& RandomEngine::getEngine( SeedType seedType, std::size_t seedValue, std::initializer_list<std::size_t> list ) {
return getMinStd_Rand0( seedType, seedValue, list );
}
template<>
static std::minstd_rand& RandomEngine::getEngine( SeedType seedType, std::size_t seedValue, std::initializer_list<std::size_t> list ) {
return getMinStd_Rand( seedType, seedValue, list );
}
template<>
static std::mt19937& RandomEngine::getEngine( SeedType seedType, std::size_t seedValue, std::initializer_list<std::size_t> list ) {
return getMt19937( seedType, seedValue, list );
}
template<>
static std::mt19937_64& RandomEngine::getEngine( SeedType seedType, std::size_t seedValue, std::initializer_list<std::size_t> list ) {
return getMt19937_64( seedType, seedValue, list );
}
template<>
static std::ranlux24& RandomEngine::getEngine( SeedType seedType, std::size_t seedValue, std::initializer_list<std::size_t> list ) {
return getRanLux24( seedType, seedValue, list );
}
template<>
static std::ranlux24_base& RandomEngine::getEngine( SeedType seedType, std::size_t seedValue, std::initializer_list<std::size_t> list ) {
return getRanLux24_base( seedType, seedValue, list );
}
template<>
static std::ranlux48& RandomEngine::getEngine( SeedType seedType, std::size_t seedValue, std::initializer_list<std::size_t> list ) {
return getRanLux48( seedType, seedValue, list );
}
template<>
static std::ranlux48_base& RandomEngine::getEngine( SeedType seedType, std::size_t seedValue, std::initializer_list<std::size_t> list ) {
return getRanLux48_base( seedType, seedValue, list );
}
首先,这些专业似乎可以正确编译和工作。当我开始为
RandomDistribution
类成员遵循类似的模式时,我开始遇到麻烦。
这些列表比上面的引擎长得多,但是此类中的每个函数都是静态函数模板,因为不同的发行版采用不同的类型,并且它们的构造函数具有不同的参数。
这个类在上面的相同头文件中,它看起来像这样,我将其限制为几个示例:
class RandomDistribution {
public:
RandomDistriubtion() = delete;
// UNIFORM DISTRIBUTIONS
template<class IntType = int>
static std::uniform_int_distribution<IntType>& getUniformIntDistribution( IntType lowerBound = 0, IntType upperBound = (std::numeric_limits<IntType>::max)() ) {
static std::uniform_int_distribution<IntType> dist( lowerBound, upperBound );
return dist;
}
template<class RealType = double>
static std::uniform_real_distribution<RealType>& getUniformRealDistribution( RealType lowerBound = 0.0, RealType upperBound = 1.0 ) {
static std::uniform_real_distribution<RealType> dist( lowerBound, upperBound );
return dist;
}
[...] // More distributions here
template<class RealType = double, class InputIt1, class InputIt2>
static std::piecewise_linear_distribution<RealType>& getPiecewiseLinearDistribution( InputIt1 first_i, InputIt1 last_i, InputIt2 first_w ) {
static std::piecewise_linear_distribution<RealType> dist( first_i, last_i, first_w );
return dist;
}
template<class RealType = double, class UnaryOperation>
static std::piecewise_linear_distribution<RealType>& getPiecewiseLinearDistribution( std::initializer_list<RealType> bl, UnaryOperation fw ) {
static std::piecewise_linear_distribution<RealType> dist( bl, fw );
return dist;
}
template<class RealType = double, class UnaryOperation>
static std::piecewise_linear_distribution<RealType>& getPiecewiseLinearDistribution( std::size_t nw, RealType xmin, RealType xmax, UnaryOperation fw ) {
static std::piecewise_linear_distribution<RealType> dist( nw, xmin, xmax, fw );
return dist;
}
// function template with variadic pamater for specialization.
getDistribution() ... see below
};
从上面的类中可以看到一长串的发行版;所有这些静态方法均按原样运行;但是我想做的和我使用
RandomEngine
函数一样。我想创建一个功能模板,然后专门化每个。唯一的原因是,其中一些采用不同的类型,例如
Real
和
Int
,而某些采用2个参数,而其他则可以采用3个或更多。我需要为此功能使用可变参数模板。
在上面
RandomDistriubtion
类的公共部分中,我进行了这种声明/定义尝试。
template<class Type, template<typename = Type> class Distribution, class... DistParams>
static Distribution<Type>& getDistribution( DistParams... params ) {
return getUniformIntDistribution( params... );
}
我在cpp文件中写专业化的第一次尝试如下所示:
// specializations of different distributions
template<>
static std::uniform_real_distribution<>& RandomDistribution::getDistribution() {
return RandomDistribution::getUniformRealDistribution();
}
除了专业之外,我还拥有一个独立的函数模板,该模板在两个typedef之后的头文件底部进行了声明定义:
// Made some edits to this function template; I changed the template
// paramater for `Type` from `class` to `typename` and I changed the
// local variable declarations to have static storage instead.
// I also added a forgotten return to `Type retVal`
// I also fixed the call to `getDistribution` by changing its
// template parameter list to `<Type, Distribution>` as suggested
// by user max66 which allowed me to move further ahead.
template<class Engine, typename Type, template<typename = Type> class Distribution, class... DistParams>
Type randomGenerator( RE::SeedType seedType, std::size_t seedValue, std::initializer_list<std::size_t> list, DistParams... params ) {
static Type retVal = 0;
static Engine engine = RE::getEngine<Engine>( seedType, seedValue, list );
static Distribution<Type> dist = RD::getDistribution<Distribution<Type>>( params... );
retVal = dist( engine );
return retVal;
}
我正在尝试从此函数模板中的上述2个类调用通用函数。基本上,我正在尝试将过程简化为一个函数调用,以使用任何提供的可通过任何播种类型进行播种的引擎来生成任何类型的随机分布,它将生成并返回随机值
type T
。
这就是它的主要外观。
#include "RandomGenerator.h"
int main() {
std::initializer_list<std::size_t> list{};
unsigned val = randomGenerator<std::mt19937, unsigned, std::uniform_int_distribution >
( RE::USE_CHRONO_CLOCK, std::size_t( 12 ), list, 1, 100 );
return 0;
}
当我编译RandomGenerator.cpp时,它编译没有错误,但是当我编译main.cpp时,我得到了这些编译器错误:
1>------ Build started: Project: ChemLab, Configuration: Debug Win32 ------
1>main.cpp
1>c:\...\visual studio 2017\projects\chemlab\engine\randomgenerator.h(599): error C2672: 'linx::RandomDistribution::getDistribution': no matching overloaded function found
1>c:\...\visual studio 2017\projects\chemlab\chemlab\main.cpp(13): note: see reference to function template instantiation 'Type linx::randomGenerator<std::mt19937,unsigned int,std::uniform_int_distribution,int,int>(linx::RandomEngine::SeedType,::size_t,std::initializer_list<_Ty>,int,int)' being compiled
1> with
1> [
1> Type=unsigned int,
1> _Ty=std::seed_seq::result_type
1> ]
1>c:\...\visual studio 2017\projects\chemlab\engine\randomgenerator.h(596): error C2783: 'Distribution<Type> &linx::RandomDistribution::getDistribution(DistParams...)': could not deduce template argument for 'Distribution'
1>c:\...\visual studio 2017\projects\chemlab\engine\randomgenerator.h(577): note: see declaration of 'linx::RandomDistribution::getDistribution'
1>Done building project "ChemLab.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
我知道错误是什么意思,第一个错误是没有匹配的重载,第二个错误无法推断出
Distribution
的模板参数。
我只是不知道是什么真正导致了它们,以及如何解决这些编译器错误。它是template template参数吗?它具有基础类型吗?是否带有可变参数包?如果我能使一些专业工作的话;我应该能够得到其余的。
我知道这是很多事情,但我确实感谢那些花时间阅读和阅读本文的人。任何想法都欢迎。
编辑-我已经从旧版本的Visual Studio VS2015带来了这个类库,但是原始项目可能是在2010、2012或2013版本中编写的...从
RandomEngine
类中,我必须删除
getSeedSeq
函数因为在2017年,复制构造函数和移动构造函数被删除了。您可以忽略类中用于设置引擎的那部分。我改为在适当的case语句中创建
seed_seq
的实例,并将
initializer_list
传递给其构造函数。然后,我将该静态实例传递给
engine.seed()
函数。只是要注意的事情。并且它没有更改编译器错误,在此修复程序之后它们仍然相同。
编辑好吧,我根据用户max66的建议对功能模板
randomGenerator()
进行了一些更正;您可以在上面的代码部分中看到这一点。
现在我有了这些修复程序;我遇到了稍微不同的编译器错误。
error C2440: 'return': cannot convert from 'std::uniform_int_distribution<int>' to 'std::uniform_int_distribution<Type> &'
因此,现在它无法从
uniform_int_distriubtion<int>&
转换为
uniform_int_distribution<Type>&
。因此,现在我试图找出如何正确进行转换。
我是一名优秀的程序员,十分优秀!