So I've been interested by the mersenne_twister engine and what it can do, so I decided to put the few lines of code required to initialize it inside my own class so that i simply have to create an instance of that class and can get any random numbers in any range i want without having to repeat those lines every time I need it.
I have suceeded so far but because I want my code to be as portble and efficient as possible I want to use the 64-bit engine depending on the architecture present. I would like to avoid the way of using preprocessor macros defined by the compiler as that doesn't seem like the cleanest approach to me and would also require me to use the macros every time i mention the engine in my code.
My macro for the architecture l looks like this:
#define CPU_ARCH sizeof(nullptr)*8
And I declare the engine in the private space of the class so that i can init it in the constructor like this:
engine = mt19937(seed);
and use it in my random function like this:
double Random::giveRnd() {
return distribution(engine);
}
This looks fine right now but I have yet to find a way to implement both architectures with the same name "engine" in a way that the engine to be used is chosen at startup.
I have attempted the following:
Using a template to create a variable named engine that later gets
assigned either mt19337 or mt19337_64 which results in the compiler
complaining that
error: data member 'engine' cannot be a member template
with the following implementation:
class Random {
public:
[...]
private:
template<typename T>
T engine;
[...]
};
Using preprocessor macros in the header file and then use typeid in
the source code to find out which engine was used, which doesn't seem
to be possible like this:
if(CPU_ARCH==32) { engine = mt19337(seed) }
because the compiler doesn't know that the engine will always be
32-bit in this case and complains that I cannot use the '=' operator
on two different types.
Does anyone have an idea on how to make this possible in a atleast somewhat clean way? Or do I need to fall back on the preprocessor macros?
You can implement behaviour that depends on CPU_BITS
by making a class template that takes CPU_BITS
as a template argument, and is specialized for expected values. For example:
#include <random>
template<size_t N> struct CpuOpts;
template<> struct CpuOpts<32> { using EngineType = std::mt19937; };
template<> struct CpuOpts<64> { using EngineType = std::mt19937_64; };
enum { CPU_BITS = sizeof(nullptr)*8 };
using CurrentCpuOpts = CpuOpts<CPU_BITS>;
struct Random
{
CurrentCpuOpts::EngineType engine;
};
int main()
{
Random r;
r.engine.seed(123456);
}