问题描述
我正在使用Visual Studio 2017 CE版本15.6.2,并将编译器语言选项设置为:
I'm using Visual Studio 2017 CE version 15.6.2 with compiler language options set to:
我正在使用<random>
中的大多数功能,并且我有2个不是模板类的类,分别是RandomEngine
和RandomDistribution
.
I'm working with a majority of the functions from <random>
and I have 2 classes that are non template classes, RandomEngine
and RandomDistribution
.
无法删除这些类,因为它们已删除默认构造函数.所有的方法在类中都是静态的.
These classes can not be constructed as they have deleted default constructors. All the methods are static within the classes.
在RandomEngine
类中,我的静态方法是根据标准库中的某些随机引擎(例如std::mt19937
)命名的.它支持通过传递给静态函数的枚举类型和所需的其他参数,通过不同的机制为引擎提供种子的功能.这些引擎中的任何一种都有4种播种方式:{CHRONO_CLOCK
,SEED_VALUE
,SEED_SEQ
,RANDOM_DEVICE
}.有一个具有通用名称getEngine(...)
的函数模板,使用专门化功能,我能够创建此函数,以返回每种不同类型的引擎.该课程太大了,但我将展示一些示例:
Within the RandomEngine
class my static methods are named according to some of the random engines in the standard library such as std::mt19937
. It supports the functionality to seed the engines by different mechanisms depending on the enumeration type passed into the static function and other parameters that are needed. There are 4 ways that any of these engines can be seeded: {CHRONO_CLOCK
, SEED_VALUE
, SEED_SEQ
, RANDOM_DEVICE
}. There is one function template that has a generic name getEngine(...)
and using specialization I was able to create this function returning each of the different types of engines. The class is too big but I will show a couple of examples:
RandomGenerator.h
#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(...)
函数专门化为这样:
Then in my RandomGenerator.cpp file I specialized the RandomEngine::getEngine(...)
function as such:
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
类成员遵循类似的模式时,我开始遇到麻烦.
These specializations above all seem to compile and work correctly. It is when I begin to follow a similar pattern for my RandomDistribution
class members that I begin to get into trouble.
这些列表比上面的引擎长很多,但是此类中的每个函数都是静态函数模板,因为不同的发行版采用不同的类型,并且它们的构造函数具有不同的参数.
The list to these is a lot longer than the engines above but every function in this class is a static function template as different distributions take different types and they have different parameters for their constructors.
该类在上面的相同头文件中,它看起来像这样,我将其限制为几个示例:
This class is in the same header file above and it looks like this and I'll limit it to a few examples:
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个或更多的参数;我需要为此功能使用可变参数模板.
As you can see from the class above with the long list of distributions; all of these static methods work as is; but I would like to do the same thing as I did with the RandomEngine
functions. I want to create a function template then specialize each of these. The only thing is because some of these take different types such as Real
& Int
and some take 2 parameters while others can take 3 or more; I need to use variadic templates for this function.
在上面的RandomDistriubtion
类的公共部分中,我进行了这种声明/定义尝试.
In the public section of the RandomDistriubtion
class above I have this declaration/definition attempt.
template<class Type, template<typename = Type> class Distribution, class... DistParams>
static Distribution<Type>& getDistribution( DistParams... params ) {
return getUniformIntDistribution( params... );
}
我在cpp文件中编写专业化的第一次尝试如下所示:
My first attempt of writing the specializations in the cpp file is shown here:
// specializations of different distributions
template<>
static std::uniform_real_distribution<>& RandomDistribution::getDistribution() {
return RandomDistribution::getUniformRealDistribution();
}
除了专业领域外,我还拥有一个独立的函数模板,该模板在两个typedef之后的头文件底部进行了声明定义:
Besides the specializations I also have this stand alone function template that is declared-defined at the bottom of the header file after the two typedefs:
// 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
I'm trying to call the generalized functions from the 2 classes above within this function template. Basically I'm trying to streamline the process into a single function call to generate any type of random distribution using any of the provided engines that can be seeded by any of the seeding types and it will generate and return a random value of 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时,我得到了这些编译器错误:
When I compile RandomGenerator.cpp it compiles without error, but when I compile main.cpp I'm getting these compiler errors:
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
的模板参数.
I know what the errors mean the first being no matching overload, and the second could not deduce template argument for Distribution
.
我只是不知道是什么真正导致了它们,以及如何解决这些编译器错误.它是template template参数吗?它具有基础类型吗?是否带有可变参数包?如果我能使一些专业工作的话;我应该能够得到其余的东西.
I just don't know what is actually causing them and how to resolve these compiler errors. Is it the template template parameter? Is it with the underlying type? Is it with the variadic parameter pack? If I can get some of the specializations working; I should be able to get the rest.
我知道这是很多事情,但我确实感谢那些花时间阅读和阅读本文的人.任何想法都欢迎.
I know that this is a lot to take in but I do truly appreciate those who have taken the time to read and look through this. Any and all thoughts are welcome.
编辑-我已经从旧版本的Visual Studio VS2015中引入了该类库,但原始项目可能是在2010、2012或2013版本中编写的...从RandomEngine
我必须删除getSeedSeq
函数,因为在2017年,复制构造函数& move构造函数被删除了.您可以忽略类中用于设置引擎的那部分.相反,我在适当的case语句中创建了seed_seq
的实例,并将initializer_list
传递给其构造函数.然后,我将该静态实例传递给engine.seed()
函数.只是要注意的事情.并没有更改编译器错误,此修复后它们仍然相同.
EDIT - I have brought this class library over from an older version of Visual Studio VS2015 but the original project might of been written in 2010, 2012 or 2013 version... From the RandomEngine
class I had to remove the getSeedSeq
function because in 2017 the copy constructor & move constructors are deleted functions. You can ignore that part of the class for setting up the engines. I instead created an instance of a seed_seq
in the appropriate case statements and I passed the initializer_list
to its constructor. Then I passed that static instance into the engine.seed()
function. Just something to be aware of. And it did not change the compiler errors they are still the same after this fix.
编辑好吧,我根据用户max66的建议对功能模板randomGenerator()
进行了一些更正;您可以在上面的代码部分中看到这一点.
Edit Okay I made some corrects to the function template randomGenerator()
as suggested by user max66; you can see that in the code section above.
现在我有了这些修复程序;我遇到了稍微不同的编译器错误.
Now that I have those fixes; I'm getting a slightly different compiler error.
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>&
.因此,现在我试图弄清楚如何正确进行转换.
So now it's not able to convert from uniform_int_distriubtion<int>&
to uniform_int_distribution<Type>&
. So now I'm trying to figure out how to get the conversions correct.
推荐答案
我们必须使用"最小,完整且可验证的示例"的概念,我发现您的代码中存在很多问题(请:下一次准备可以编译的代码),但是Visual Studio显示的问题始于getDistribution()
定义
We have to work with the concept of "minimal, complete and verifiable example" and I see a lot of problems in your code (please: next time prepare a code that can compile) but the problem that visual studio show start from getDistribution()
definition
template <class Type,
template<typename = Type> class Distribution,
class... DistParams>
static Distribution<Type>& getDistribution( DistParams... params ) {
return getUniformIntDistribution( params... );
}
所以需要模板类型(Type
),模板-模板模板参数(Distribution
)和其他模板类型(DistParams...
)匹配方法自变量(params...
)的方法
so a method that require a template type (Type
), a template-template template parameter (Distribution
) and other template types (DistParams...
) matching the (deductibles from) methods arguments (params...
).
但是您在RandomGenerator()
中的getDistribution()
通话如下
dist = RD::getDistribution<Distribution<Type>>( params... );
因此,您明确地将类型(Distribution<Type>
)(而不是类型)和模板模板参数作为模板参数.
So you explicit, as template parameter, a type (Distribution<Type>
) not a type and a template-template parameter.
我想你打算打如下电话getDistribution()
I suppose your intention was to call getDistribution()
as follows
// first Type vvvv vvvvvvvvvvvv Distribution next
dist = RD::getDistribution<Type, Distribution>( params... );
这篇关于具有可变参数的类成员函数模板部分专业化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!