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.