jeudi 14 avril 2016

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

I am working on a class that does not instantiate an instance; it has a protected constructor and all methods are static. This class I have simplifies the calls to various random engines found in <random> I have a similar class that does the same thing for different distribution types. All of my static calls to my Engines work fine along with being able to seed them in multiple ways. I'm now in the process of working on my companion class to work with the different distributions. So far I have been able to do std::uniform_int, std::uniform_int_distribution, std::uniform_real and std::uniform_real_distribution with complete success. Now that I have started to work with std::generate_canonical I'm starting to get compiler errors.

This is what my RandomGenerator header file looks like:

#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

It is this function that I'm working on

    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 

And I've been following the syntax form this website: cppreference where they have this line of code

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

I'm trying to create and return a static instance of this distribution. The RealType in the template argument is defaulted to double which is preferred to use with std::generate_canonical and std::size_t is the number of bits int the field for the 2nd template argument, and the third template argument represents the RandomEngine generator to be passed to it. Howe I'm having trouble defining this function properly. I keep getting compiler error from 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 ==========

I've tried other ways to define this but I get very similar errors. I don't need these functions to do the actual work for that is left to be user defined, I'm just creating a simple user interface for quick easy access to create a prepared RandomEngine and a PreparedDistribution where, one instance is generated statically, yet the user still has the option to create a local variable of the type being used. Any suggestions on how to properly construct this static function is appreciated.




Aucun commentaire:

Enregistrer un commentaire