Viatorus
Viatorus

Reputation: 1903

Template specialization for float

I know, I cannot use float as non-type parameter in templates. So I would like to use a numerator and a denominator for my limit class.

My limit class gets a type and the min and max value. To use Limit for int and for float I currently use this:

template <typename U, typename T = U, T A1 = 0, T A2 = 0, T A3 = 0, T A4 = 0>
struct Limit {
  static constexpr const U min = A1;
  static constexpr const U max = A2;
};

template <intmax_t A1, intmax_t A2, intmax_t A3, intmax_t A4>
struct Limit<float, intmax_t, A1, A2, A3, A4>  {
  static constexpr const float min = A1 / (float) A2;
  static constexpr const float max = A3 / (float) A4;
};

Limit<float, intmax_t, 40, 20, 30, 40> a;

Limit<int, 10, 20> b;

Is there any way to optimize this implementation? And maybe enable default values for the float implementation?

Thank you in advance!

Edit: I would like to have an template declaration like this one (not working):

// For int, char, short, uint32_t etc...
template <typename U, U MIN, U MAX>
struct Limit {
  static constexpr const U min = MIN;
  static constexpr const U max = MAX;
};

// For float/double
template <typename T /*float or double*/, typename MIN, typename MAX>
struct Limit  {
  static constexpr const T min = MIN.num / (T) MIN.dem; // static cast...
  static constexpr const T max = MAX.num / (T) MAX.dem; // static cast...
};

Limit<int, int, 10, 20> a;

Limit<float, std::ratio<4,5>, std::ratio<10,15>> b;

Upvotes: 3

Views: 510

Answers (2)

T.C.
T.C.

Reputation: 137425

You can either always wrap it in ratios so that you'd write Limit<int, std:::ratio<100>, std::ratio<200>>...

or you can do something along the lines of

// if T is floating point, return std::intmax_t, otherwise T.
template<class T>
using adjust_floating = std::conditional_t<std::is_floating_point<T>{}, std::intmax_t, T>;

template <class T, adjust_floating<T> A1 = 0,
                   adjust_floating<T> A2 = 0,
                   adjust_floating<T> A3 = 0,
                   adjust_floating<T> A4 = 0 >
struct Limit {
    // maybe static_assert that A3 and A4 are zero if T isn't floating point
    static constexpr T min = std::is_floating_point<T>{} ? A1 / (T) A2 : A1;
    static constexpr T max = std::is_floating_point<T>{} ? A3 / (T) A4 : A2;
};

Upvotes: 1

Dimitrios Bouzas
Dimitrios Bouzas

Reputation: 42929

Your implementation I think it screams for use of std::ratio. You could use two raw std::ratio for your min and max or some implementation like below:

template<typename U, std::intmax_t NumerMin = 0, std::intmax_t DenomMin = 1,
                     std::intmax_t NumerMax = 0, std::intmax_t DenomMax = 1>
struct Limit {
  static const std::ratio<NumerMin, DenomMin> min_;
  static const std::ratio<NumerMax, DenomMax> max_;
public:
  U const min = static_cast<U>(min_.num) / static_cast<U>(min_.den);
  U const max = static_cast<U>(max_.num) / static_cast<U>(max_.den);
};

Live Demo

Upvotes: 4

Related Questions