Consider this struct. It is a range, but uses template instead of constructor, making the values static:
template <int min_v, int max_v>
struct num_range final {
constexpr static int min = min_v;
constexpr static int max = max_v;
}
// now you can do
std::cout << num_range<1,3>::min << '\n'; // prints 1
But this is fixed to int
. What if I wanted C++ to deduce the numeric type from the first argument and enforce it on the second argument?
I tried this:
template <typename TNumber>
template <TNumber min_v, TNumber max_v>
struct num_range final
I tried that at the reverse order. I know you can do this:
template <auto min_v, decltype(min_v) max_v>
struct num_range final {
using num_type = decltype(min_v);
constexpr static num_type min = min_v;
constexpr static num_type max = max_v;
};
But I don't think auto
template argument is allowed in C++17, which is what I am targeting. It also does not seem to enforce the type on the second template argument, as this compiles just fine:
std::cout << num_range<-10, 12U>::min << '\n'; // prints -10
Bonus points if you know how to do this with variadric template, enforcing all numbers to be same type.
I don't think auto template argument is allowed in C++17
It is allowed in C++17.
It also does not seem to enforce the type on the second template argument
Yes, some implicit conversions are permitted when passing template arguments. Do this instead:
template <auto min_v, auto max_v>
struct num_range
{
static_assert(std::is_same_v<decltype(min_v), decltype(max_v)>);
constexpr static auto min = min_v;
constexpr static auto max = max_v;
};
Or in C++20:
template <auto min_v, auto max_v>
requires std::is_same_v<std::is_same_v<decltype(min_v), decltype(max_v)>
struct num_range
{
constexpr static auto min = min_v;
constexpr static auto max = max_v;
};