An overloaded random number function template using modern C++
Clash Royale CLAN TAG#URR8PPP
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;
up vote
5
down vote
favorite
I don't mess around a lot with templates (or with GTK), but today I wrote something and would like to know how it can be improved, and hopefully clarify a few things in the process.
So, Randolfi()
is a function template which returns a random number. A range can be specified as arguments.
It uses features new to C++11, based on these:
How to generate a random number in C++?
Random number generation in C++11 , how to generate , how do they work?
(The name "Randolfi" is a joke made by a few colleagues regarding my last name, Ranolfi.)
randolfi.hpp
#ifndef RANDOLFI_HPP
#define RANDOLFI_HPP
#include <random>
template <typename T>
T Randolfi()
std::mt19937 rng;
rng.seed( std::random_device()() );
std::uniform_int_distribution<T> dist;
return dist(rng);
template <typename T>
T Randolfi(T range_start, T range_end)
std::mt19937 rng;
rng.seed( std::random_device()() );
std::uniform_int_distribution<T> dist(range_start, range_end);
return dist(rng);
#endif //RANDOLFI_HPP
randolfi-test.cpp
#include <iostream>
#include <string>
#include <gtkmm.h>
#include "randolfi.hpp"
using namespace std;
int main()
auto app = Gtk::Application::create();
uint a_random_number = Randolfi<uint>();
Gtk::MessageDialog dialog( to_string(a_random_number) );
dialog.run();
return 0;
Notes:
Somehow it doesn't feel right to have such a large proportion of redundant lines across the function overloads. I think there might be a template-related trick to help here, but searching for it proved useless since all the results I found (like this one) are concerned about type parameter overloading, which is not my case.
I though about declaring it as
Randolfi(T range_start = NULL, T range_end = NULL)
and then checkingif (range_start != NULL && range_end != NULL)
, but that does not save me any lines, and also appears to be frowned upon.As it is, the function can be called without type argument for the second overload, but not for the first one:
Randolfi(0, 100); // type parameter ommited for template
Randolfi(); // Fails - compiler has no clue on know how to instantiate templateI have a feeling this inconsistency is bad practice.
I'm mostly concerned about the template header, but I did include my testing code (randolfi-test.cpp) to this question so maybe someone can let me know if I did something terribly wrong. From my part, I'd like to avoid calling
Gtk::Application::create()
but that doesn't seem to be possible.
Thanks!
c++ random template-meta-programming gtk
add a comment |Â
up vote
5
down vote
favorite
I don't mess around a lot with templates (or with GTK), but today I wrote something and would like to know how it can be improved, and hopefully clarify a few things in the process.
So, Randolfi()
is a function template which returns a random number. A range can be specified as arguments.
It uses features new to C++11, based on these:
How to generate a random number in C++?
Random number generation in C++11 , how to generate , how do they work?
(The name "Randolfi" is a joke made by a few colleagues regarding my last name, Ranolfi.)
randolfi.hpp
#ifndef RANDOLFI_HPP
#define RANDOLFI_HPP
#include <random>
template <typename T>
T Randolfi()
std::mt19937 rng;
rng.seed( std::random_device()() );
std::uniform_int_distribution<T> dist;
return dist(rng);
template <typename T>
T Randolfi(T range_start, T range_end)
std::mt19937 rng;
rng.seed( std::random_device()() );
std::uniform_int_distribution<T> dist(range_start, range_end);
return dist(rng);
#endif //RANDOLFI_HPP
randolfi-test.cpp
#include <iostream>
#include <string>
#include <gtkmm.h>
#include "randolfi.hpp"
using namespace std;
int main()
auto app = Gtk::Application::create();
uint a_random_number = Randolfi<uint>();
Gtk::MessageDialog dialog( to_string(a_random_number) );
dialog.run();
return 0;
Notes:
Somehow it doesn't feel right to have such a large proportion of redundant lines across the function overloads. I think there might be a template-related trick to help here, but searching for it proved useless since all the results I found (like this one) are concerned about type parameter overloading, which is not my case.
I though about declaring it as
Randolfi(T range_start = NULL, T range_end = NULL)
and then checkingif (range_start != NULL && range_end != NULL)
, but that does not save me any lines, and also appears to be frowned upon.As it is, the function can be called without type argument for the second overload, but not for the first one:
Randolfi(0, 100); // type parameter ommited for template
Randolfi(); // Fails - compiler has no clue on know how to instantiate templateI have a feeling this inconsistency is bad practice.
I'm mostly concerned about the template header, but I did include my testing code (randolfi-test.cpp) to this question so maybe someone can let me know if I did something terribly wrong. From my part, I'd like to avoid calling
Gtk::Application::create()
but that doesn't seem to be possible.
Thanks!
c++ random template-meta-programming gtk
There are numerous reviews of such code. See for instance: codereview.stackexchange.com/questions/190552/â¦
â papagaga
Apr 13 at 8:01
add a comment |Â
up vote
5
down vote
favorite
up vote
5
down vote
favorite
I don't mess around a lot with templates (or with GTK), but today I wrote something and would like to know how it can be improved, and hopefully clarify a few things in the process.
So, Randolfi()
is a function template which returns a random number. A range can be specified as arguments.
It uses features new to C++11, based on these:
How to generate a random number in C++?
Random number generation in C++11 , how to generate , how do they work?
(The name "Randolfi" is a joke made by a few colleagues regarding my last name, Ranolfi.)
randolfi.hpp
#ifndef RANDOLFI_HPP
#define RANDOLFI_HPP
#include <random>
template <typename T>
T Randolfi()
std::mt19937 rng;
rng.seed( std::random_device()() );
std::uniform_int_distribution<T> dist;
return dist(rng);
template <typename T>
T Randolfi(T range_start, T range_end)
std::mt19937 rng;
rng.seed( std::random_device()() );
std::uniform_int_distribution<T> dist(range_start, range_end);
return dist(rng);
#endif //RANDOLFI_HPP
randolfi-test.cpp
#include <iostream>
#include <string>
#include <gtkmm.h>
#include "randolfi.hpp"
using namespace std;
int main()
auto app = Gtk::Application::create();
uint a_random_number = Randolfi<uint>();
Gtk::MessageDialog dialog( to_string(a_random_number) );
dialog.run();
return 0;
Notes:
Somehow it doesn't feel right to have such a large proportion of redundant lines across the function overloads. I think there might be a template-related trick to help here, but searching for it proved useless since all the results I found (like this one) are concerned about type parameter overloading, which is not my case.
I though about declaring it as
Randolfi(T range_start = NULL, T range_end = NULL)
and then checkingif (range_start != NULL && range_end != NULL)
, but that does not save me any lines, and also appears to be frowned upon.As it is, the function can be called without type argument for the second overload, but not for the first one:
Randolfi(0, 100); // type parameter ommited for template
Randolfi(); // Fails - compiler has no clue on know how to instantiate templateI have a feeling this inconsistency is bad practice.
I'm mostly concerned about the template header, but I did include my testing code (randolfi-test.cpp) to this question so maybe someone can let me know if I did something terribly wrong. From my part, I'd like to avoid calling
Gtk::Application::create()
but that doesn't seem to be possible.
Thanks!
c++ random template-meta-programming gtk
I don't mess around a lot with templates (or with GTK), but today I wrote something and would like to know how it can be improved, and hopefully clarify a few things in the process.
So, Randolfi()
is a function template which returns a random number. A range can be specified as arguments.
It uses features new to C++11, based on these:
How to generate a random number in C++?
Random number generation in C++11 , how to generate , how do they work?
(The name "Randolfi" is a joke made by a few colleagues regarding my last name, Ranolfi.)
randolfi.hpp
#ifndef RANDOLFI_HPP
#define RANDOLFI_HPP
#include <random>
template <typename T>
T Randolfi()
std::mt19937 rng;
rng.seed( std::random_device()() );
std::uniform_int_distribution<T> dist;
return dist(rng);
template <typename T>
T Randolfi(T range_start, T range_end)
std::mt19937 rng;
rng.seed( std::random_device()() );
std::uniform_int_distribution<T> dist(range_start, range_end);
return dist(rng);
#endif //RANDOLFI_HPP
randolfi-test.cpp
#include <iostream>
#include <string>
#include <gtkmm.h>
#include "randolfi.hpp"
using namespace std;
int main()
auto app = Gtk::Application::create();
uint a_random_number = Randolfi<uint>();
Gtk::MessageDialog dialog( to_string(a_random_number) );
dialog.run();
return 0;
Notes:
Somehow it doesn't feel right to have such a large proportion of redundant lines across the function overloads. I think there might be a template-related trick to help here, but searching for it proved useless since all the results I found (like this one) are concerned about type parameter overloading, which is not my case.
I though about declaring it as
Randolfi(T range_start = NULL, T range_end = NULL)
and then checkingif (range_start != NULL && range_end != NULL)
, but that does not save me any lines, and also appears to be frowned upon.As it is, the function can be called without type argument for the second overload, but not for the first one:
Randolfi(0, 100); // type parameter ommited for template
Randolfi(); // Fails - compiler has no clue on know how to instantiate templateI have a feeling this inconsistency is bad practice.
I'm mostly concerned about the template header, but I did include my testing code (randolfi-test.cpp) to this question so maybe someone can let me know if I did something terribly wrong. From my part, I'd like to avoid calling
Gtk::Application::create()
but that doesn't seem to be possible.
Thanks!
c++ random template-meta-programming gtk
edited Apr 13 at 3:28
asked Apr 13 at 3:22
Marc.2377
1326
1326
There are numerous reviews of such code. See for instance: codereview.stackexchange.com/questions/190552/â¦
â papagaga
Apr 13 at 8:01
add a comment |Â
There are numerous reviews of such code. See for instance: codereview.stackexchange.com/questions/190552/â¦
â papagaga
Apr 13 at 8:01
There are numerous reviews of such code. See for instance: codereview.stackexchange.com/questions/190552/â¦
â papagaga
Apr 13 at 8:01
There are numerous reviews of such code. See for instance: codereview.stackexchange.com/questions/190552/â¦
â papagaga
Apr 13 at 8:01
add a comment |Â
2 Answers
2
active
oldest
votes
up vote
4
down vote
accepted
The constructor of uniform_int_distribution
has default arguments:
template<typename T>
explicit uniform_int_distribution(T a = 0,
T b = std::numeric_limits<T>::max());
(I don't know why a
defaults to 0 rather than to the minimum T
, but there you go).
You can reduce your duplication by using the same default arguments, and passing them through to this constructor:
template <typename T>
T Randolfi(T range_start = 0,
T range_end = std::numeric_limits<T>::max())
std::uniform_int_distribution<T> dist(range_start, range_end);
return dist(rng);
Or, we can use perfect forwarding to create the distribution with the same arguments as passed in:
template <typename T, typename... Args>
T Randolfi(Args&&... args)
std::uniform_int_distribution<T> dist(std::forward<Args>(args)...);
return dist(rng);
We'll need to do this if we want to support a variety of distributions, so it's probably the way to go.
Don't recreate a random generator every call. You could make it static
, which will reduce that to once per instantiation, but it's better to keep it outside of the function, so you only create and seed it once per process.
In the test program, you should exercise more than one type T
, and test with implicit and explicit range. Also, avoid using namespace std;
, and prefer tests which don't require a GUI environment (so they can be more easily run on build servers).
Modified code
#include <limits>
#include <random>
#include <utility>
static auto rng =
std::mt19937 rng;
rng.seed(std::random_device()());
return rng;
();
template <typename T,
template<typename> typename Distribution
= std::uniform_int_distribution,
typename... Args>
T Randolfi(Args&&... args)
Distribution<T> dist(std::forward<Args>(args)...);
return dist(rng);
#include <iostream>
int main()
std::clog << Randolfi<int>(-100, +100) << 'n'
<< Randolfi<char>('a', 'z') << 'n'
<< Randolfi<double, std::normal_distribution>(100, 15) << 'n'
<< Randolfi<std::size_t>() << std::endl;
I'm not sure of what you meant with "We'll need to [ use perfect forwarding ] if we want to support a variety of distributions". As is, perfect forwarding integers seems curious.
â papagaga
Apr 13 at 11:40
your code won't compile btw.Randolfi
signatures overlap (ambiguous).
â papagaga
Apr 13 at 11:41
Thanks @papagaga - copy/paste error - I've now removed the accidental extra copy of theuniform_int_distribution
version.
â Toby Speight
Apr 13 at 12:34
As to your comment - not all distributions take the same number of arguments. For example,std::poisson_distribution
accepts only one argument, so couldn't be called with 0 and max in the same way. Forwarding a parameter pack is the only way to support the variable number of arguments required. The perfect part of it is probably now a habit - although I got it wrong (writing(Args...)
instead of(Args&&...)
), and I got no compiler warning for usingstd::forward
with an argument not of universal-reference type - gcc wishlist!
â Toby Speight
Apr 13 at 12:39
About the first idea, I had thought about that, but didn't feel too confortable with duplicating code from the standard library. But in retrospect, well, that's not really such a big problem, I think. About the second idea (perfect forwarding), that's awesome. Didn't know that. Good insight with your suggestion about not recreating the random generator on every function call. (continues)
â Marc.2377
May 23 at 4:36
 |Â
show 4 more comments
up vote
3
down vote
As it stands right now, every time you need a random number, you're creating a new instance of std::mt19937
, then using std::random_device
to seed this instance, then (finally) getting a number and returning it.
What you (nearly always) want to do is create one instance of std::mt19937
, seed it once, and then re-use the same generator throughout the remainder of the program.
As it stands now, you'd be much better off just using std::random_device
to generate the number (without using std::mt19937
at all):
template <typename T>
T Randolfi()
return std::random_device()();
...at which point, the code might as well not exist at all, because it's not adding anything to what std::random_device
provides out of the box.
About your last sentence, it was supposed to be a convenience function with type guarantee. At least that makes for an advantage, no?
â Marc.2377
May 23 at 4:45
add a comment |Â
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
4
down vote
accepted
The constructor of uniform_int_distribution
has default arguments:
template<typename T>
explicit uniform_int_distribution(T a = 0,
T b = std::numeric_limits<T>::max());
(I don't know why a
defaults to 0 rather than to the minimum T
, but there you go).
You can reduce your duplication by using the same default arguments, and passing them through to this constructor:
template <typename T>
T Randolfi(T range_start = 0,
T range_end = std::numeric_limits<T>::max())
std::uniform_int_distribution<T> dist(range_start, range_end);
return dist(rng);
Or, we can use perfect forwarding to create the distribution with the same arguments as passed in:
template <typename T, typename... Args>
T Randolfi(Args&&... args)
std::uniform_int_distribution<T> dist(std::forward<Args>(args)...);
return dist(rng);
We'll need to do this if we want to support a variety of distributions, so it's probably the way to go.
Don't recreate a random generator every call. You could make it static
, which will reduce that to once per instantiation, but it's better to keep it outside of the function, so you only create and seed it once per process.
In the test program, you should exercise more than one type T
, and test with implicit and explicit range. Also, avoid using namespace std;
, and prefer tests which don't require a GUI environment (so they can be more easily run on build servers).
Modified code
#include <limits>
#include <random>
#include <utility>
static auto rng =
std::mt19937 rng;
rng.seed(std::random_device()());
return rng;
();
template <typename T,
template<typename> typename Distribution
= std::uniform_int_distribution,
typename... Args>
T Randolfi(Args&&... args)
Distribution<T> dist(std::forward<Args>(args)...);
return dist(rng);
#include <iostream>
int main()
std::clog << Randolfi<int>(-100, +100) << 'n'
<< Randolfi<char>('a', 'z') << 'n'
<< Randolfi<double, std::normal_distribution>(100, 15) << 'n'
<< Randolfi<std::size_t>() << std::endl;
I'm not sure of what you meant with "We'll need to [ use perfect forwarding ] if we want to support a variety of distributions". As is, perfect forwarding integers seems curious.
â papagaga
Apr 13 at 11:40
your code won't compile btw.Randolfi
signatures overlap (ambiguous).
â papagaga
Apr 13 at 11:41
Thanks @papagaga - copy/paste error - I've now removed the accidental extra copy of theuniform_int_distribution
version.
â Toby Speight
Apr 13 at 12:34
As to your comment - not all distributions take the same number of arguments. For example,std::poisson_distribution
accepts only one argument, so couldn't be called with 0 and max in the same way. Forwarding a parameter pack is the only way to support the variable number of arguments required. The perfect part of it is probably now a habit - although I got it wrong (writing(Args...)
instead of(Args&&...)
), and I got no compiler warning for usingstd::forward
with an argument not of universal-reference type - gcc wishlist!
â Toby Speight
Apr 13 at 12:39
About the first idea, I had thought about that, but didn't feel too confortable with duplicating code from the standard library. But in retrospect, well, that's not really such a big problem, I think. About the second idea (perfect forwarding), that's awesome. Didn't know that. Good insight with your suggestion about not recreating the random generator on every function call. (continues)
â Marc.2377
May 23 at 4:36
 |Â
show 4 more comments
up vote
4
down vote
accepted
The constructor of uniform_int_distribution
has default arguments:
template<typename T>
explicit uniform_int_distribution(T a = 0,
T b = std::numeric_limits<T>::max());
(I don't know why a
defaults to 0 rather than to the minimum T
, but there you go).
You can reduce your duplication by using the same default arguments, and passing them through to this constructor:
template <typename T>
T Randolfi(T range_start = 0,
T range_end = std::numeric_limits<T>::max())
std::uniform_int_distribution<T> dist(range_start, range_end);
return dist(rng);
Or, we can use perfect forwarding to create the distribution with the same arguments as passed in:
template <typename T, typename... Args>
T Randolfi(Args&&... args)
std::uniform_int_distribution<T> dist(std::forward<Args>(args)...);
return dist(rng);
We'll need to do this if we want to support a variety of distributions, so it's probably the way to go.
Don't recreate a random generator every call. You could make it static
, which will reduce that to once per instantiation, but it's better to keep it outside of the function, so you only create and seed it once per process.
In the test program, you should exercise more than one type T
, and test with implicit and explicit range. Also, avoid using namespace std;
, and prefer tests which don't require a GUI environment (so they can be more easily run on build servers).
Modified code
#include <limits>
#include <random>
#include <utility>
static auto rng =
std::mt19937 rng;
rng.seed(std::random_device()());
return rng;
();
template <typename T,
template<typename> typename Distribution
= std::uniform_int_distribution,
typename... Args>
T Randolfi(Args&&... args)
Distribution<T> dist(std::forward<Args>(args)...);
return dist(rng);
#include <iostream>
int main()
std::clog << Randolfi<int>(-100, +100) << 'n'
<< Randolfi<char>('a', 'z') << 'n'
<< Randolfi<double, std::normal_distribution>(100, 15) << 'n'
<< Randolfi<std::size_t>() << std::endl;
I'm not sure of what you meant with "We'll need to [ use perfect forwarding ] if we want to support a variety of distributions". As is, perfect forwarding integers seems curious.
â papagaga
Apr 13 at 11:40
your code won't compile btw.Randolfi
signatures overlap (ambiguous).
â papagaga
Apr 13 at 11:41
Thanks @papagaga - copy/paste error - I've now removed the accidental extra copy of theuniform_int_distribution
version.
â Toby Speight
Apr 13 at 12:34
As to your comment - not all distributions take the same number of arguments. For example,std::poisson_distribution
accepts only one argument, so couldn't be called with 0 and max in the same way. Forwarding a parameter pack is the only way to support the variable number of arguments required. The perfect part of it is probably now a habit - although I got it wrong (writing(Args...)
instead of(Args&&...)
), and I got no compiler warning for usingstd::forward
with an argument not of universal-reference type - gcc wishlist!
â Toby Speight
Apr 13 at 12:39
About the first idea, I had thought about that, but didn't feel too confortable with duplicating code from the standard library. But in retrospect, well, that's not really such a big problem, I think. About the second idea (perfect forwarding), that's awesome. Didn't know that. Good insight with your suggestion about not recreating the random generator on every function call. (continues)
â Marc.2377
May 23 at 4:36
 |Â
show 4 more comments
up vote
4
down vote
accepted
up vote
4
down vote
accepted
The constructor of uniform_int_distribution
has default arguments:
template<typename T>
explicit uniform_int_distribution(T a = 0,
T b = std::numeric_limits<T>::max());
(I don't know why a
defaults to 0 rather than to the minimum T
, but there you go).
You can reduce your duplication by using the same default arguments, and passing them through to this constructor:
template <typename T>
T Randolfi(T range_start = 0,
T range_end = std::numeric_limits<T>::max())
std::uniform_int_distribution<T> dist(range_start, range_end);
return dist(rng);
Or, we can use perfect forwarding to create the distribution with the same arguments as passed in:
template <typename T, typename... Args>
T Randolfi(Args&&... args)
std::uniform_int_distribution<T> dist(std::forward<Args>(args)...);
return dist(rng);
We'll need to do this if we want to support a variety of distributions, so it's probably the way to go.
Don't recreate a random generator every call. You could make it static
, which will reduce that to once per instantiation, but it's better to keep it outside of the function, so you only create and seed it once per process.
In the test program, you should exercise more than one type T
, and test with implicit and explicit range. Also, avoid using namespace std;
, and prefer tests which don't require a GUI environment (so they can be more easily run on build servers).
Modified code
#include <limits>
#include <random>
#include <utility>
static auto rng =
std::mt19937 rng;
rng.seed(std::random_device()());
return rng;
();
template <typename T,
template<typename> typename Distribution
= std::uniform_int_distribution,
typename... Args>
T Randolfi(Args&&... args)
Distribution<T> dist(std::forward<Args>(args)...);
return dist(rng);
#include <iostream>
int main()
std::clog << Randolfi<int>(-100, +100) << 'n'
<< Randolfi<char>('a', 'z') << 'n'
<< Randolfi<double, std::normal_distribution>(100, 15) << 'n'
<< Randolfi<std::size_t>() << std::endl;
The constructor of uniform_int_distribution
has default arguments:
template<typename T>
explicit uniform_int_distribution(T a = 0,
T b = std::numeric_limits<T>::max());
(I don't know why a
defaults to 0 rather than to the minimum T
, but there you go).
You can reduce your duplication by using the same default arguments, and passing them through to this constructor:
template <typename T>
T Randolfi(T range_start = 0,
T range_end = std::numeric_limits<T>::max())
std::uniform_int_distribution<T> dist(range_start, range_end);
return dist(rng);
Or, we can use perfect forwarding to create the distribution with the same arguments as passed in:
template <typename T, typename... Args>
T Randolfi(Args&&... args)
std::uniform_int_distribution<T> dist(std::forward<Args>(args)...);
return dist(rng);
We'll need to do this if we want to support a variety of distributions, so it's probably the way to go.
Don't recreate a random generator every call. You could make it static
, which will reduce that to once per instantiation, but it's better to keep it outside of the function, so you only create and seed it once per process.
In the test program, you should exercise more than one type T
, and test with implicit and explicit range. Also, avoid using namespace std;
, and prefer tests which don't require a GUI environment (so they can be more easily run on build servers).
Modified code
#include <limits>
#include <random>
#include <utility>
static auto rng =
std::mt19937 rng;
rng.seed(std::random_device()());
return rng;
();
template <typename T,
template<typename> typename Distribution
= std::uniform_int_distribution,
typename... Args>
T Randolfi(Args&&... args)
Distribution<T> dist(std::forward<Args>(args)...);
return dist(rng);
#include <iostream>
int main()
std::clog << Randolfi<int>(-100, +100) << 'n'
<< Randolfi<char>('a', 'z') << 'n'
<< Randolfi<double, std::normal_distribution>(100, 15) << 'n'
<< Randolfi<std::size_t>() << std::endl;
edited Apr 13 at 12:40
answered Apr 13 at 10:46
Toby Speight
17.5k13489
17.5k13489
I'm not sure of what you meant with "We'll need to [ use perfect forwarding ] if we want to support a variety of distributions". As is, perfect forwarding integers seems curious.
â papagaga
Apr 13 at 11:40
your code won't compile btw.Randolfi
signatures overlap (ambiguous).
â papagaga
Apr 13 at 11:41
Thanks @papagaga - copy/paste error - I've now removed the accidental extra copy of theuniform_int_distribution
version.
â Toby Speight
Apr 13 at 12:34
As to your comment - not all distributions take the same number of arguments. For example,std::poisson_distribution
accepts only one argument, so couldn't be called with 0 and max in the same way. Forwarding a parameter pack is the only way to support the variable number of arguments required. The perfect part of it is probably now a habit - although I got it wrong (writing(Args...)
instead of(Args&&...)
), and I got no compiler warning for usingstd::forward
with an argument not of universal-reference type - gcc wishlist!
â Toby Speight
Apr 13 at 12:39
About the first idea, I had thought about that, but didn't feel too confortable with duplicating code from the standard library. But in retrospect, well, that's not really such a big problem, I think. About the second idea (perfect forwarding), that's awesome. Didn't know that. Good insight with your suggestion about not recreating the random generator on every function call. (continues)
â Marc.2377
May 23 at 4:36
 |Â
show 4 more comments
I'm not sure of what you meant with "We'll need to [ use perfect forwarding ] if we want to support a variety of distributions". As is, perfect forwarding integers seems curious.
â papagaga
Apr 13 at 11:40
your code won't compile btw.Randolfi
signatures overlap (ambiguous).
â papagaga
Apr 13 at 11:41
Thanks @papagaga - copy/paste error - I've now removed the accidental extra copy of theuniform_int_distribution
version.
â Toby Speight
Apr 13 at 12:34
As to your comment - not all distributions take the same number of arguments. For example,std::poisson_distribution
accepts only one argument, so couldn't be called with 0 and max in the same way. Forwarding a parameter pack is the only way to support the variable number of arguments required. The perfect part of it is probably now a habit - although I got it wrong (writing(Args...)
instead of(Args&&...)
), and I got no compiler warning for usingstd::forward
with an argument not of universal-reference type - gcc wishlist!
â Toby Speight
Apr 13 at 12:39
About the first idea, I had thought about that, but didn't feel too confortable with duplicating code from the standard library. But in retrospect, well, that's not really such a big problem, I think. About the second idea (perfect forwarding), that's awesome. Didn't know that. Good insight with your suggestion about not recreating the random generator on every function call. (continues)
â Marc.2377
May 23 at 4:36
I'm not sure of what you meant with "We'll need to [ use perfect forwarding ] if we want to support a variety of distributions". As is, perfect forwarding integers seems curious.
â papagaga
Apr 13 at 11:40
I'm not sure of what you meant with "We'll need to [ use perfect forwarding ] if we want to support a variety of distributions". As is, perfect forwarding integers seems curious.
â papagaga
Apr 13 at 11:40
your code won't compile btw.
Randolfi
signatures overlap (ambiguous).â papagaga
Apr 13 at 11:41
your code won't compile btw.
Randolfi
signatures overlap (ambiguous).â papagaga
Apr 13 at 11:41
Thanks @papagaga - copy/paste error - I've now removed the accidental extra copy of the
uniform_int_distribution
version.â Toby Speight
Apr 13 at 12:34
Thanks @papagaga - copy/paste error - I've now removed the accidental extra copy of the
uniform_int_distribution
version.â Toby Speight
Apr 13 at 12:34
As to your comment - not all distributions take the same number of arguments. For example,
std::poisson_distribution
accepts only one argument, so couldn't be called with 0 and max in the same way. Forwarding a parameter pack is the only way to support the variable number of arguments required. The perfect part of it is probably now a habit - although I got it wrong (writing (Args...)
instead of (Args&&...)
), and I got no compiler warning for using std::forward
with an argument not of universal-reference type - gcc wishlist!â Toby Speight
Apr 13 at 12:39
As to your comment - not all distributions take the same number of arguments. For example,
std::poisson_distribution
accepts only one argument, so couldn't be called with 0 and max in the same way. Forwarding a parameter pack is the only way to support the variable number of arguments required. The perfect part of it is probably now a habit - although I got it wrong (writing (Args...)
instead of (Args&&...)
), and I got no compiler warning for using std::forward
with an argument not of universal-reference type - gcc wishlist!â Toby Speight
Apr 13 at 12:39
About the first idea, I had thought about that, but didn't feel too confortable with duplicating code from the standard library. But in retrospect, well, that's not really such a big problem, I think. About the second idea (perfect forwarding), that's awesome. Didn't know that. Good insight with your suggestion about not recreating the random generator on every function call. (continues)
â Marc.2377
May 23 at 4:36
About the first idea, I had thought about that, but didn't feel too confortable with duplicating code from the standard library. But in retrospect, well, that's not really such a big problem, I think. About the second idea (perfect forwarding), that's awesome. Didn't know that. Good insight with your suggestion about not recreating the random generator on every function call. (continues)
â Marc.2377
May 23 at 4:36
 |Â
show 4 more comments
up vote
3
down vote
As it stands right now, every time you need a random number, you're creating a new instance of std::mt19937
, then using std::random_device
to seed this instance, then (finally) getting a number and returning it.
What you (nearly always) want to do is create one instance of std::mt19937
, seed it once, and then re-use the same generator throughout the remainder of the program.
As it stands now, you'd be much better off just using std::random_device
to generate the number (without using std::mt19937
at all):
template <typename T>
T Randolfi()
return std::random_device()();
...at which point, the code might as well not exist at all, because it's not adding anything to what std::random_device
provides out of the box.
About your last sentence, it was supposed to be a convenience function with type guarantee. At least that makes for an advantage, no?
â Marc.2377
May 23 at 4:45
add a comment |Â
up vote
3
down vote
As it stands right now, every time you need a random number, you're creating a new instance of std::mt19937
, then using std::random_device
to seed this instance, then (finally) getting a number and returning it.
What you (nearly always) want to do is create one instance of std::mt19937
, seed it once, and then re-use the same generator throughout the remainder of the program.
As it stands now, you'd be much better off just using std::random_device
to generate the number (without using std::mt19937
at all):
template <typename T>
T Randolfi()
return std::random_device()();
...at which point, the code might as well not exist at all, because it's not adding anything to what std::random_device
provides out of the box.
About your last sentence, it was supposed to be a convenience function with type guarantee. At least that makes for an advantage, no?
â Marc.2377
May 23 at 4:45
add a comment |Â
up vote
3
down vote
up vote
3
down vote
As it stands right now, every time you need a random number, you're creating a new instance of std::mt19937
, then using std::random_device
to seed this instance, then (finally) getting a number and returning it.
What you (nearly always) want to do is create one instance of std::mt19937
, seed it once, and then re-use the same generator throughout the remainder of the program.
As it stands now, you'd be much better off just using std::random_device
to generate the number (without using std::mt19937
at all):
template <typename T>
T Randolfi()
return std::random_device()();
...at which point, the code might as well not exist at all, because it's not adding anything to what std::random_device
provides out of the box.
As it stands right now, every time you need a random number, you're creating a new instance of std::mt19937
, then using std::random_device
to seed this instance, then (finally) getting a number and returning it.
What you (nearly always) want to do is create one instance of std::mt19937
, seed it once, and then re-use the same generator throughout the remainder of the program.
As it stands now, you'd be much better off just using std::random_device
to generate the number (without using std::mt19937
at all):
template <typename T>
T Randolfi()
return std::random_device()();
...at which point, the code might as well not exist at all, because it's not adding anything to what std::random_device
provides out of the box.
answered Apr 13 at 3:44
Jerry Coffin
27.4k360123
27.4k360123
About your last sentence, it was supposed to be a convenience function with type guarantee. At least that makes for an advantage, no?
â Marc.2377
May 23 at 4:45
add a comment |Â
About your last sentence, it was supposed to be a convenience function with type guarantee. At least that makes for an advantage, no?
â Marc.2377
May 23 at 4:45
About your last sentence, it was supposed to be a convenience function with type guarantee. At least that makes for an advantage, no?
â Marc.2377
May 23 at 4:45
About your last sentence, it was supposed to be a convenience function with type guarantee. At least that makes for an advantage, no?
â Marc.2377
May 23 at 4:45
add a comment |Â
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f191928%2fan-overloaded-random-number-function-template-using-modern-c%23new-answer', 'question_page');
);
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
There are numerous reviews of such code. See for instance: codereview.stackexchange.com/questions/190552/â¦
â papagaga
Apr 13 at 8:01