3

I was trying to write a class that will fill a container with random numbers with the type that the container has:

template<typename random_type> class rand_helper { private: std::mt19937 random_engine; std::uniform_int_distribution<int> int_dist; std::uniform_real_distribution<double> real_dist; public: rand_helper() = delete; rand_helper(random_type left_b, random_type right_b); random_type operator()(); }; template<typename random_type> rand_helper<random_type>::rand_helper(const random_type left_b, const random_type right_b) :random_engine{ std::random_device{}()} { if constexpr (std::is_same_v<random_type, double>) real_dist(left_b, right_b ); else int_dist( left_b, right_b ); } template<typename random_type> random_type rand_helper<random_type>::operator()() { if constexpr (std::is_same_v<random_type, double>) return real_dist(random_engine); else return int_dist(random_engine); } 

But here an error occurs somewhere, because when I call std::generate,then I get a lot of errors:

template<typename T,typename vec_type = typename T::value_type> void fill_contain(T& container,vec_type left_b=vec_type(0), vec_type right_b= vec_type(100)) { std::generate(std::begin(container),std::end(container), rand_helper<vec_type>(left_b ,right_b)); } 

I thought it might be because of if constexpr but if just leave:

template<typename random_type> random_type rand_helper<random_type>::operator()() { return int_dist(random_engine); } 

then the same errors are still returned. Here is the list of errors I get:

Error C2825 '_Urng': must be a class or namespace when followed by '::' Error C2510 '_Urng' : left of '::' must be a class / struct / union Error C2061 syntax error : identifier 'result_type' Error C2065 '_Ty1' : undeclared identifier Error C2923 'std::conditional_t' : '_Ty1' is not a valid template type argument for parameter '_Ty2' 

The function call goes like this:

 std::vector<int> for_sort; fill_contain(for_sort); 
2
  • 1
    Reopened: This question is clearly not asking how to generate random numbers at compile-time, and none of the answers there explain this compiler error. Commented May 29, 2021 at 16:58
  • @chris Oh, you're right, I misread the question. That was a careless closure, thanks for catching it. Commented May 29, 2021 at 17:07

2 Answers 2

5

Your code just doesn't compile, regardless of the if constexpr. The reason you may not be getting a compilation error with just the template class is that, well, it's a template, so no actual instance of anything gets compiled. If you add:

template class rand_helper<int>; 

which forces an instantiation for a random_type of int, you'll get plenty of compilation error output.

Specifically, you'll be told that you need a pseudo-randomness generator to construct a uniform_int_distribution<int>.


Regardless of the above - you can use something like:

template <typename T> using uniform_distribution = std::conditional_t< std::is_integral_v<T>, std::uniform_int_distribution<T>, std::uniform_real_distribution<T> >; 

to only have just one distribution member. And in that case, you might not even need your helper class.

Sign up to request clarification or add additional context in comments.

5 Comments

that is, you can use std:: conditional together with std::uniform_int_distribution and std::uniform_real_distribution? As far as I remember, it outputs a general type from several, here it can also be done from such elements?
@Alpharius: Yes.
I can't even imagine how it should work.I thought that it was possible to select a type through the template .it would be very interesting to see an example of what you are talking about
Thank you so much,I didn't even think about it.That is, in your opinion, it is better to use your uniform_distribution and define a random generator somewhere in the lambda function (for example) than to make functors?
@Alpharius: I'd go with lambda to start with.
2

To avoid instantiating the std::uniform_real_distribution template class with a non-floating-point type and getting a potentially confusing diagnostic, I'd prefer to use template specializations like this rather than std::conditional_t:

namespace detail { template <typename T, typename AlwaysVoid = void> struct uniform_distribution_impl { static_assert(sizeof(T) == 0, "T must be integral or floating point"); }; template <typename T> struct uniform_distribution_impl< T, std::enable_if_t<std::is_integral_v<T>>> { using type = std::uniform_int_distribution<T>; }; template <typename T> struct uniform_distribution_impl< T, std::enable_if_t<std::is_floating_point_v<T>>> { using type = std::uniform_real_distribution<T>; }; } template <typename T> using uniform_distribution = typename detail::uniform_distribution_impl<T>::type; 

1 Comment

great addition!

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.