I have a template that accepts class F
and int X
. Class F has a static inline double eval(double x)
method. Based on the result returned by eval
I need to choose between int
and long
types - smallest possible that will fit the result (converted to a round number as it's double).
I tried doing it this way but I get Non-type template argument is not a constant expression
error.
template <class F, int X>
struct DEDUCTOR {
typedef SELECT<-32768 < F::eval(X) && F::eval(X) < 32767> result;
}
where SELECT
is defined this way:
template <bool is_int>
struct SELECT {};
template <>
struct SELECT<true> {
typedef int type;
};
template <>
struct SELECT<false> {
typedef long type;
};
Is there any way to create such template?
============================ UPDATE:
According to the advice, I added constexpr to the eval
function. It works now, but now always. Full example:
#include <iostream>
#include <math.h>
#include <typeinfo>
struct X {
static constexpr double eval(double x) { return x; };
};
template<class L, class R>
struct MULT {
static constexpr double eval(double x) {
return L::eval(x) * R::eval(x);
}
};
template<class L, class R>
struct DIV {
static constexpr double eval(double x) {
return L::eval(x) / R::eval(x);
}
};
template <bool is_int>
struct SELECT {
typedef long type;
};
template <>
struct SELECT<true> {
typedef int type;
};
template<class F, int X>
struct DEDUCTOR {
typedef typename SELECT<-32768 < F::eval(X) && F::eval(X) < 32767>::type result;
};
int main() {
// typedef MULT<MULT<X, X>, X> F; // works
typedef DIV<DIV<X, X>, X> F; // doesn't work
typedef DEDUCTOR<F, 0> deductor;
std::cout << typeid(deductor::result).name() << std::endl;
return 0;
}