功能模板参数在编译期间无法转换类型 [英] Function template parameters failing to convert type during compilation
问题描述
尝试使用调用类的专用静态函数模板的函数模板时,无法从模板参数列表中转换其参数.
While trying to use a function template that calls a class's specialized static function template it is failing to convert its parameter from the template parameter list.
这是我在main中调用的函数:
Here is the function that I'm calling in main:
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<Type, Distribution>( params... );
retVal = dist( engine );
return retVal;
}
有关上述功能的一些信息:
A little bit about the function above:
Type
表示Integral Types
的分布的返回值,例如int
,unsigned
,char
等,适用于uniform_int_distribution<IntType>
或Real Types
的分布,例如double
用于类似uniform_real_distribution<RealType>
的发行版.
The Type
represents the return value of the distribution such as int
, unsigned
, char
, etc for Integral Types
that work with distributions such as uniform_int_distribution<IntType>
or Real Types
such as float
, double
for distributions like uniform_real_distribution<RealType>
.
条款RE
& RD
是两个类的typedef.
The terms RE
& RD
are typedefs of two classes.
typedef RandomEngine RE;
typedef RandomDistribution RD;
两个类都遵循相同的模式,因为它们具有delete构造函数,并且它们的所有方法都声明为静态.
Both classes follow the same pattern as they have delete constructors and all of their methods are declared a static.
函数的第二行使用模板参数<class Engine>
表示我们要从class RandomEngine{...}
的静态方法中使用的<random>
头文件中的哪种引擎.每种引擎类型都有其自己的功能来创建引擎,通过播种类型和种子值为其播种,然后返回引擎的引用. RandomEngine class
中的所有功能都是非模板功能.因此,我接着在此RandomEngine class
中制作了通用功能模板RE::getEngine<Engine>( parameters );
,您可以在此功能模板randomGenerator()
中看到该模板.然后,我针对每种发动机类型专门设置了此功能.我这样做没有问题.
The 2nd line in the function is using the template parameter <class Engine>
to represent what kind of engine from the <random>
header file we want to use from the static methods in class RandomEngine{...}
. Each of the engine types has it's own function to create an engine, seed it by the seeding type and seed values and then returns a reference of the engine. All of the functions in the RandomEngine class
are non template functions. So I then went ahead and made generalized function template RE::getEngine<Engine>( parameters );
in this RandomEngine class
that you can see in this function template randomGenerator()
. Then I specialized this function for each engine type. I had no problems with doing that.
这使我进入RandomDistribution class
的下一行,我尝试遵循与RandomEngine
类似的模式,我制作了一个通用函数模板RD::getDistribution<Type, Distribution>( params... );
This brings me to the next line with the RandomDistribution class
I'm trying to follow a similar pattern as I did with the RandomEngine
I made a generalized function template RD::getDistribution<Type, Distribution>( params... );
在使用RD::getDistribution<...>(...)
函数之前,以上两个类都是非模板的.第一类RandomEngine
除了通用的getEngine()
以外,其引擎具有零个功能模板,与RandomDistribution
相比,该类的区别在于该类中的每个函数都是一个功能模板,因为<random>
库的分布功能需要它.因此,现在我不仅必须像对getEngine()
那样对通用函数进行模板化,还必须使用可变参数包,因为不同的分布采用不同数量的参数.
Before I get to the RD::getDistribution<...>(...)
function both of the classes above are non templates. The first class RandomEngine
has zero function templates for its engines except the generalized getEngine()
The difference with this class as opposed to the RandomDistribution
is that every function in this class is a function template, because the <random>
library's distribution functions require it. So now I have to not only template this generalized function as I did for getEngine()
I have to also use a variadic parameter pack as different distributions takes a different amount of arguments.
这是我在头文件中找到的RandomDistribution
类中的通用函数的声明:
Here is my declaration of my generalized function in the RandomDistribution
class that is found in the header file:
template<typename Type, template<typename = Type> class Distribution, class... DistParams>
static Distribution<Type>& getDistribution( DistParams... params ) {
return getUniformIntDistribution( params... );
}
然后我尝试在cpp文件中对此功能进行专门化,以用于其他发行版之一:
Then I have this attempt of a specialization for this function in the cpp file for just one of the other distributions:
template<>
static std::uniform_real_distribution<>& RandomDistribution::getDistribution() {
return RandomDistribution::getUniformRealDistribution();
}
我想对我支持的所有其他发行版执行此操作.
I would like to do this for all the other distributions that I'm supporting.
我正在这样的主要功能中使用独立功能模板randomGenerator()
:
I am using the stand alone function template randomGenerator()
in my main function like this:
{
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 );
std::cout << val << std::endl;
}
当我编译RandomGenerator.cpp
文件时,它会编译而不会出现错误;
但是,当我编译main.cpp
时,出现编译器错误,指出它无法从std::uniform_int_distribution<int>&
转换为std::uniform_int_distribution<Type>&
When I compile RandomGenerator.cpp
file it compiles without error;
however, when I compile main.cpp
I am getting a compiler error stating that it can not convert from std::uniform_int_distribution<int>&
to std::uniform_int_distribution<Type>&
,它指向在RandomGenerator.h
文件中声明的我的类的通用函数模板.
and it is pointing to my class's generalized function template that is declared in RandomGenerator.h
file.
由于某种原因; Type
未分配或强制转换为传递到randomGenerator's
模板参数列表的类型.
For some reason; Type
is not being assigned or casted to the type that is passed into randomGenerator's
template parameter list.
我被困在这一点上.我知道编译器消息在说什么;我没有该怎么做来修复.如何解决此转换失败?
I'm stuck at this point. I know what the compiler message is saying; I don't what to do to fix. What can be done to resolve this conversion failure?
推荐答案
好吧,请您废弃上面的全部想法:我去了,将类完全重写为一个类.现在,类本身就是一个类模板.它看起来像这样:
Okay scrap that whole idea above: I went and entirely rewritten my classes into a single class. The class itself is now a class template. And it looks like this:
#ifndef GENERATOR_H
#define GENERATOR_H
#include <limits>
#include <chrono>
#include <random>
#include <type_traits>
enum SeedType { USE_CHRONO_CLOCK, USE_RANDOM_DEVICE, USE_SEED_VALUE, USE_SEED_SEQ };
template<class Engine, class Type, template<typename> class Distribution>
class Generator {
public:
using Clock = std::conditional_t<std::chrono::high_resolution_clock::is_steady,
std::chrono::high_resolution_clock,
std::chrono::steady_clock>;
private:
Engine _engine;
Distribution<Type> _distribution;
Type _value;
public:
template<class... Params>
explicit Generator( Engine engine, Params... params ) : _engine( engine ) {
_distribution = Distribution<Type>( params... );
}
void seed( SeedType type = USE_RANDOM_DEVICE, std::size_t seedValue = 0, std::initializer_list<std::size_t> list = {} ) {
switch( type ) {
case USE_CHRONO_CLOCK: { _engine.seed( getTimeNow() ); break; }
case USE_RANDOM_DEVICE: { std::random_device device{};
_engine.seed( device() ); break; }
case USE_SEED_VALUE: { _engine.seed( seedValue ); break; }
case USE_SEED_SEQ: { std::seed_seq seq( list );
_engine.seed( seq ); break; }
}
}
void generate() {
_value = _distribution( _engine );
}
Type getGeneratedValue() const {
return _value;
}
Distribution<Type> getDistribution() const {
return _distribution;
}
std::size_t getTimeNow() {
std::size_t now = static_cast<std::size_t>(Clock::now().time_since_epoch().count());
return now;
}
};
#endif // !GENERATOR_H
使用起来很简单:
#include <iostream>
#include <iomanip>
#include <vector>
#include "generator.h"
int main() {
// Engine, Seeding Type, & Distribution Combo 1
std::mt19937 engine1;
Generator<std::mt19937, short, std::uniform_int_distribution> g1( engine1, 1, 100 );
g1.seed( USE_RANDOM_DEVICE );
std::vector<short> vals1;
for( unsigned int i = 0; i < 200; i++ ) {
g1.generate();
auto v = g1.getGeneratedValue();
vals1.push_back( v );
}
int i = 0;
for( auto& v : vals1 ) {
if( (i % 10) != 0 ) {
std::cout << std::setw( 3 ) << v << " ";
} else {
std::cout << '\n' << std::setw( 3 ) << v << " ";
}
i++;
}
std::cout << "\n\n";
// Engine, Seeding Type, & Distribution Combo 2
std::ranlux48 engine2;
std::initializer_list<std::size_t> list2{ 3, 7, 13, 17, 27, 31, 43 };
Generator<std::ranlux48, unsigned, std::binomial_distribution> g2( engine2, 50, 0.75 );
g2.seed( USE_SEED_SEQ, std::size_t(7), list2 );
std::vector<unsigned> vals2;
for( int i = 0; i < 200; i++ ) {
g2.generate();
auto v = g2.getGeneratedValue();
vals2.push_back( v );
}
for( auto& v : vals2 ) {
if( (i % 10) != 0 ) {
std::cout << std::setw( 3 ) << v << " ";
} else {
std::cout << '\n' << std::setw( 3 ) << v << " ";
}
i++;
}
std::cout << "\n\n";
// Engine, Seeding Type, & Distribution Combo 3
std::minstd_rand engine3;
Generator<std::minstd_rand, float, std::gamma_distribution> g3( engine3, 0.22222f, 0.7959753f );
g3.seed( USE_CHRONO_CLOCK );
std::vector<float> vals3;
for( int i = 0; i < 200; i++ ) {
g3.generate();
auto v = g3.getGeneratedValue();
vals3.push_back( v );
}
for( auto& v : vals3 ) {
if( (i % 5 ) != 0 ) {
std::cout << std::setw( 12 ) << v << " ";
} else {
std::cout << '\n' << std::setw( 12 ) << v << " ";
}
i++;
}
std::cout << "\n\n";
std::cout << "\nPress any key and enter to quit.\n";
std::cin.get();
return 0;
}
这篇关于功能模板参数在编译期间无法转换类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!