功能模板参数在编译期间无法转换类型 [英] 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的分布的返回值,例如intunsignedchar等,适用于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.hfile.

由于某种原因; 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆