在 class 接口内的模板化静态方法中使用 std::generator_canonical

Working with std::generator_canonical in a templated static method within a class interface

我正在开发 class 不实例化实例;它有一个受保护的构造函数,所有方法都是静态的。这个 class 我简化了对 <random> 中发现的各种随机引擎的调用 我有一个类似的 class 对不同的分布类型做同样的事情。我对我的引擎的所有静态调用都可以正常工作,并且能够以多种方式对它们进行播种。我现在正在开发我的同伴 class 来处理不同的发行版。到目前为止,我已经能够完成 std::uniform_intstd::uniform_int_distributionstd::uniform_realstd::uniform_real_distribution 并取得圆满成功。现在我已经开始使用 std::generate_canonical 我开始遇到编译器错误。

这是我的 RandomGenerator 头文件的样子:

#ifndef RANDOM_GENERATOR_H
#define RANDOM_GENERATOR_H

#include <chrono>
#include <random>

class RandomEngine {
public:
    using Clock = std::conditional_t<std::chrono::high_resolution_clock::is_steady,
        std::chrono::high_resolution_clock,
        std::chrono::steady_clock>;

    // Used To Determine Which Seeding Process To Use
    enum SeedType {
        USE_CHRONO_CLOCK,
        USE_RANDOM_DEVICE,
        USE_SEED_VALUE, 
        USE_SEED_SEQ,
    }; // SeedType

    // This Enum Is Not In Use - It Is A Visual Reference Only; But If User Wants To
    // Use It For Their Own Pupose They Are Free To Do So.
    enum EngineType {
        // Default Random Engine
        DEFAULT_RANDOM_ENGINE,

        // Linear Congruential Engines
        MINSTD_RAND0,
        MINSTD_RAND,

        // Mersenne Twister Engines 
        MT19937,
        MT19937_64,

        // Subtract With Carry Engines 
        RANLUX24_BASE,
        RANLUX48_BASE,

        // Discard Block Engines 
        RANLUX24,
        RANLUX48,

        // Shuffle Order Engines
        KNUTH_B,

    }; // EngineType

protected:
    RandomEngine(){}

public:
    static unsigned int getTimeNow() {
        unsigned int now = static_cast<unsigned int>(Clock::now().time_since_epoch().count());
        return now;
    } // getTimeNow

    static std::random_device& getRandomDevice() {
        static std::random_device device{};
        return device;
    } // getRandomDevice

    static std::default_random_engine& getDefaultRandom( SeedType type, unsigned seedValue = 0, std::seed_seq& seq = std::seed_seq{} ) {
        static std::default_random_engine engine{};

        if ( type == USE_RANDOM_DEVICE ) {
            engine.seed( getRandomDevice()() );
        }

        if ( type == USE_CHRONO_CLOCK ) {
            engine.seed( getTimeNow() );
        }

        if ( type == USE_SEED_VALUE ) {
            engine.seed( seedValue );
        }

        if ( type == USE_SEED_SEQ ) {
            engine.seed( seq );
        }

        return engine;
    } // getDefaultEngine

    static std::minstd_rand0& getMinStd_Rand0( SeedType type, unsigned seedValue = 0 ) {
        static std::minstd_rand0 engine{};

        if ( type == USE_RANDOM_DEVICE ) {
            engine.seed( getRandomDevice()() );
        }

        if ( type == USE_CHRONO_CLOCK ) {
            engine.seed( getTimeNow() );
        }

        if ( type == USE_SEED_VALUE ) {
            engine.seed( seedValue );
        }
        return engine;
    } // getMinStd_Rand0

    static std::minstd_rand& getMinStd_Rand( SeedType type, unsigned seedValue = 0 ) {
        static std::minstd_rand engine{};

        if ( type == USE_RANDOM_DEVICE ) {
            engine.seed( getRandomDevice()() );
        }

        if ( type == USE_CHRONO_CLOCK ) {
            engine.seed( getTimeNow() );
        }

        if ( type == USE_SEED_VALUE ) {
            engine.seed( seedValue );
        }

        return engine;
    } // getMinStd_Rand

    static std::mt19937& getMt19937( SeedType type, unsigned seedValue = 0 ) {
        static std::mt19937 engine{};

        if ( type == USE_RANDOM_DEVICE ) {
            engine.seed( getRandomDevice()() );
        }

        if ( type == USE_CHRONO_CLOCK ) {
            engine.seed( getTimeNow() );
        }

        if (type == USE_SEED_VALUE) {
            engine.seed( seedValue );
        }

        return engine;
    } //getMt19937

    static std::mt19937_64& getMt19937_64( SeedType type, unsigned seedValue = 0 ) {
        static std::mt19937_64 engine{};

        if (type == USE_RANDOM_DEVICE) {
            engine.seed(getRandomDevice()());
        }

        if (type == USE_CHRONO_CLOCK) {
            engine.seed(getTimeNow());
        }

        if (type == USE_SEED_VALUE) {
            engine.seed(seedValue);
        }

        return engine;
    } // getMt19937_64

    static std::ranlux24_base& getRanLux24_base( SeedType type, unsigned seedValue = 0 ) {
        static std::ranlux24_base engine{};

        if ( type == USE_RANDOM_DEVICE ) {
            engine.seed( getRandomDevice()() );
        }

        if ( type == USE_CHRONO_CLOCK ) {
            engine.seed( getTimeNow() );
        }

        if ( type == USE_SEED_VALUE ) {
            engine.seed( seedValue );
        }

        return engine;
    } // getRanLux24_base

    static std::ranlux48_base& getRanLux48_base( SeedType type, unsigned seedValue = 0 ) {
        static std::ranlux48_base engine{};

        if ( type == USE_RANDOM_DEVICE ) {
            engine.seed( getRandomDevice()() );
        }

        if ( type == USE_CHRONO_CLOCK ) {
            engine.seed( getTimeNow() );
        }

        if ( type == USE_SEED_VALUE ) {
            engine.seed( seedValue );
        }

        return engine;
    } // getRanLux48_base

    static std::ranlux24& getRanLux24( SeedType type, unsigned seedValue = 0 ) {
        static std::ranlux24 engine{};

        if ( type == USE_RANDOM_DEVICE ) {
            engine.seed( getRandomDevice()() );
        }

        if ( type == USE_CHRONO_CLOCK ) {
            engine.seed( getTimeNow() );
        }

        if ( type == USE_SEED_VALUE ) {
            engine.seed( seedValue );
        }

        return engine;
    } // getRanLux24

    static std::ranlux48& getRanLux48( SeedType type, unsigned seedValue = 0 ) {
        static std::ranlux48 engine{};

        if ( type == USE_RANDOM_DEVICE ) {
            engine.seed( getRandomDevice()() );
        }

        if ( type == USE_CHRONO_CLOCK ) {
            engine.seed( getTimeNow() );
        }

        if ( type == USE_SEED_VALUE ) {
            engine.seed( seedValue );
        }

        return engine;
    } //getRanLux48

}; // RandomEngine

class RandomDistribution {
public:
    // This Enum Is Not In Use - It Is A Visual Reference Only; But If User Wants To
    // Use It For Their Own Pupose They Are Free To Do So.
    enum DistributionType {
        // Uniform Distributions
        UNIFORM_INT,
        UNIFORM_INT_DISTRIBUTION,
        UNIFORM_REAL,
        UNIFORM_REAL_DISTRIBUTION,
        GENERATE_CANONICAL,

        // Bernoulli Distributions
        BERNOULLI_DISTRIBUTION,
        BINOMAIL_DISTRIBUTION,
        NEGATIVE_BINOMIAL_DISTRIBUTION,
        GEOMETRIC_DISTRIBUTION,

        // Poisson Distributions
        POISSON_DISTRIBUTION,
        EXPONENTIAL_DISTRIBUTION,
        GAMMA_DISTRIBUTION,
        WEIBULL_DISTRIBUTION,
        EXTREME_VALUE_DISTRIBUTION,

        // Normal Distributions
        NORMAL_DISTRIBUTION,
        LOGNORMAL_DISTRIBUTION,
        CHI_SQUARED_DISTRIBUTION,
        CAUCHY_DISTRIBUTION,
        FISHER_F_DISTRIBUTION,
        STUDENT_T_DISTRIBUTION,

        // Sampling Distributions
        DISCRETE_DISTRIBUTION,
        PIECEWISE_CONSTANT_DISTRIBUTION,
        PIECEWISE_LINEAR_DISTRIBUTION
    }; // DistributionType

protected:
    RandomDistribution(){}

public:
    template<class IntType = int>
    static std::uniform_int<IntType>& getUniformInt( IntType lowerBound, IntType upperBound ) {
        static std::uniform_int<IntType> dist( lowerBound, upperBound );
        return dist;
    } // getUniformInt

    template<class IntType = int>
    static std::uniform_int<IntType>& getUniformIntDistribution( IntType lowerBound, IntType upperBound ) {
        static std::uniform_int_distribution<IntType> dist( lowerBound, upperBound );
        return dist;
    } // getUniformIntDistribution

    template<class RealType = double>
    static std::uniform_real<RealType>& getUniformReal( RealType lowerBound, RealType upperBound ) {
        static std::uniform_real<RealType> dist( lowerBound, uppperBound );
        return dist;
    } // getUniformReal

    template<class RealType = double>
    static std::uniform_real_distribution<RealType>& getUniformRealDistribution( RealType lowerBound, RealType upperBound ) {
        static std::uniform_real_distribution<RealType> dist( lowerBound, upperBound );
        return dist;
    } // getUniformRealDistribution

    template<class RealType = double, std::size_t numBits, class Generator>
    static std::generate_canonical<RealType, numBits>& getGenerateCanonical( Generator& engine ) {
        static std::generate_canonical<RealType, numBits> dist( engine );
        return dist;
    } // getGeneratorCanonical    

}; // RandomDistribution

typedef RandomEngine RE;
typedef RandomDistribution RD;

// #include "RandomGeneator.inl"

#endif // RANDOM_GENERATOR_H

我正在开发的就是这个功能

    template<class RealType = double, std::size_t numBits, class Generator>
    static std::generate_canonical<RealType, numBits>& getGenerateCanonical( Generator& engine ) {
        static std::generate_canonical<RealType, numBits> dist( engine );
        return dist;
    } // getGeneratorCanonical 

我一直遵循这个网站的语法:cppreference 他们有这行代码

std::cout << std::generate_canonical<double, 10>(gen) << ' ';

我正在尝试创建并 return 此发行版的静态实例。模板参数中的 RealType 默认为 double,最好与 std::generate_canonical 一起使用,std::size_t 是第二个模板参数字段中的位数,第三个模板参数表示 RandomEngine 生成器传递给它。 Howe 我无法正确定义此功能。我不断收到来自 VS2015

的编译器错误
1>------ Build started: Project: DieRoll, Configuration: Debug Win32 ------
1>  RandomGenerator.cpp
1>c:\users\skilz80\documents\visual studio 2015\projects\dieroll\dieroll\randomgenerator.h(297): error C2988: unrecognizable template declaration/definition
1>c:\users\skilz80\documents\visual studio 2015\projects\dieroll\dieroll\randomgenerator.h(297): error C2143: syntax error: missing ';' before '&'
1>c:\users\skilz80\documents\visual studio 2015\projects\dieroll\dieroll\randomgenerator.h(297): error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
1>c:\users\skilz80\documents\visual studio 2015\projects\dieroll\dieroll\randomgenerator.h(297): error C2365: 'std::generate_canonical': redefinition; previous definition was 'function'
1>  c:\program files (x86)\microsoft visual studio 14.0\vc\include\random(295): note: see declaration of 'std::generate_canonical'
1>c:\users\skilz80\documents\visual studio 2015\projects\dieroll\dieroll\randomgenerator.h(297): error C2238: unexpected token(s) preceding ';'
1>c:\users\skilz80\documents\visual studio 2015\projects\dieroll\dieroll\randomgenerator.h(297): error C2059: syntax error: '&'
1>c:\users\skilz80\documents\visual studio 2015\projects\dieroll\dieroll\randomgenerator.h(304): error C2143: syntax error: missing ';' before '}'
1>c:\users\skilz80\documents\visual studio 2015\projects\dieroll\dieroll\randomgenerator.h(304): error C2238: unexpected token(s) preceding ';'
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

我试过其他方法来定义它,但我得到了非常相似的错误。我不需要这些功能来完成实际工作,因为它留给了用户定义,我只是创建一个简单的用户界面,以便快速轻松地创建一个准备好的 RandomEngine 和一个 PreparedDistribution,其中静态生成一个实例,但是用户仍然可以选择创建正在使用的类型的局部变量。任何有关如何正确构造此静态函数的建议都将受到赞赏。

编辑 感谢 ildjarn 提到 std::generate_canonical 是一个函数而不是 class 模板。当我回到我所引用的网站时,他们确实以小绿色文本将其列为函数模板,而不是 class 模板。既然我直接知道它是什么,我就可以从我的 class 中省略它而不用担心它。现在,这消除了我在无法编译时遇到的一些困惑。

编辑

我终于完成了我的 class 并合并了所有主要发行版并测试了它们,它们似乎都可以正常工作。我还删除了 std::uniform_intstd::uniform_real,因为它们只是各自分布的基础 classes。

std::generate_canonical 是函数,不是类型。