I have this function which opens /dev/urand and reads into a pointer of size; however it’s very C like and not very C++ like. I want to make the function look more like modern C++.
void URand::getrandom(uint64_t* r,uint8_t s){
FILE* f = fopen("/dev/urandom","rb");
assert(f);
switch (s) {
case 8:
fread(r,sizeof(uint8_t),1,f);
break;
case 16:
fread(r,sizeof(uint16_t),1,f);
break;
case 32:
fread(r,sizeof(uint32_t),1,f);
break;
case 64:
fread(r,sizeof(uint64_t),1,f);
break;
default:
break;
}
fclose(f);
}
So the first issue is I’m passing uint64_t if I might not even need a variable of that size , if I only need 1 byte then I should pass in uint8, or 2 bytes then uint16.
The other is I’m passing in the number of bits needed to be read. Can this be automated?
Can I for example pass in the type(uint8_t) as an argument itself so the function knows which type its dealing with and the size its dealing with? I can’t do sizeof(r) because r is a pointer.
Maybe function overloading could be a solution where I have a different type for each argument?
void URand::getrandom(uint8_t* r);
void URand::getrandom(uint16_t* r);
void URand::getrandom(uint32_t* r);
void URand::getrandom(uin64_t* r);
I get that’s a more pleasant solution than what I have; however I think with modern C++ it could be done even nicer and cleaner.
>Solution :
I would probably do something like this:
template<typename Unsigned>
Unsigned dev_urandom()
{
Unsigned u;
std::ifstream("/dev/urandom", std::ios::binary).read((char*)&u, sizeof(u));
return u;
}
int main()
{
std::cout << dev_urandom<unsigned int>() << '\n';
}
Or, if you prefer:
template<typename Unsigned>
void dev_urandom(Unsigned& u)
{
std::ifstream("/dev/urandom", std::ios::binary).read((char*)&u, sizeof(u));
}
int main()
{
unsigned u;
dev_urandom(u);
std::cout << u << '\n';
}