-1

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.

EDIT Thanks to ildjarn by mentioning that std::generate_canonical is a function and not a class template. When I went back to the website I was referencing they did have it listed in small green text as being a function template instead of being a class template. Now that I know what it is directly, I can just omit this from my class and not worry about it. This now clears up the bit of confusion I was having when I wasn't able to get it to compile.

EDIT

I finally have my class complete and have incorporated all of the major distributions and have tested them and they all appear to be working correctly. I also removed the std::uniform_int and std::uniform_real since they are only base classes to their respective distributions.

Francis Cugler
  • 7,788
  • 2
  • 28
  • 59

1 Answers1

1

std::generate_canonical is a function, not a type.

ildjarn
  • 62,044
  • 9
  • 127
  • 211
  • So you are saying that it it isn't the same as the other distributions such as std::uniform_int_distribution and std::uniform_real_distribution? I didn't find much on it other than the fact it returns a value between [0,1) . So I'm guessing with this information about it I could just omit it from my class or change my function to be a function that just returns the value and invokes this function call. – Francis Cugler Apr 15 '16 at 04:28
  • 2
    `generate_canonical` isn't a distribution; I don't know what gave you the impression that it is. If your intent is to support all distributions then ignoring `generate_canonical` is indeed the right thing to do. :-] – ildjarn Apr 15 '16 at 04:34
  • I was going through the header and it is defined in there and also this website page here http://en.cppreference.com/w/cpp/numeric/random lists it under the uniform distribution section, so that was what I was initially gathering. It random returns a value between [0,1) on RealTypes, but if float is used it has the caveat of returning a 1 on different compilers. ... – Francis Cugler Apr 15 '16 at 05:06
  • (...continued) If you are saying that it isn't a distribution, then I don't know why that website lists it as such, but after you had mentioned that it was a function and I went back to that site, it is in small green text that it is a function template and not a class template in which I had over looked. So yes I can just omit it. – Francis Cugler Apr 15 '16 at 05:10
  • 1
    @FrancisCugler : I don't know why either; a bug on the wiki, it seems, as [this page](http://en.cppreference.com/w/cpp/header/random) correctly separates it from the actual distributions. – ildjarn Apr 15 '16 at 06:10
  • 1
    It's all good! Part of the learning curve is making mistakes and learning from them; gaining experience is remembering to not make the same mistake twice; and gaining wisdom is learning from other's mistakes. – Francis Cugler Apr 15 '16 at 10:33
  • 2
    @ildjarn now separated from the distributions in that page too – Cubbi Apr 16 '16 at 13:39