0

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;
}
bumbur
  • 302
  • 3
  • 9
  • 1
    Not unless `eval()` is a `constexpr` function that can be evaluated at compile time. Because that's when templates get instantiated. – Sam Varshavchik Mar 02 '19 at 15:28
  • @SamVarshavchik I tried adding ‘constexpr’ in front of the function as it is compile time evaluated but it still displays same error. – bumbur Mar 02 '19 at 15:38
  • Please post a [mcve]. – melpomene Mar 02 '19 at 15:44
  • That means that the function is not a constant function, therefore it cannot be used in a template parameter. C++ simply doesn't work this way. – Sam Varshavchik Mar 02 '19 at 15:53
  • I try as `static constexpr double eval(double x) { return 0.0; }`, and i got no errors. Could you check this out? Or.. i guess your `eval()` function is not possible to calculate in compile time. In this case, `eval()` can't be `constexpr`. – RammerChoi Mar 02 '19 at 15:53
  • I updated my answer to include full example. – bumbur Mar 02 '19 at 17:54

1 Answers1

1

Your main problem is this line:

typedef SELECT<-32768 < F::eval(X) && F::eval(X) < 32767> result;

it should be:

typedef typename SELECT < -32768 < F::eval(X) && F::eval(X) < 32767 > ::type result;

NOTE: trailing "::type" to actually refer to the type from your SELECT structs, and leading "typename" since it's a dependent type.

Below is a working version. Note that I slightly changed the SELECT as well, but this isn't required to compile.

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;
};

struct myS
{
    static constexpr double eval(double x) { return x; }
};

int main()
{
    std::cout << typeid(DEDUCTOR<myS, 100>::result).name() << std::endl;
    std::cout << typeid(DEDUCTOR<myS, 100000>::result).name() << std::endl;
}
David
  • 602
  • 5
  • 14
  • you are dividing by zero after your update. change it to 1 and it works. [see here] https://stackoverflow.com/questions/29222319/constexpr-variable-and-division – David Mar 02 '19 at 19:02
  • Ah yes, I chose a wrong example :D Thank you anyway, I managed to figure out that the last issue was in the other implementation of eval() which used pow function. I needed to implement it myself. Thanks a lot, you helped me a lot! – bumbur Mar 02 '19 at 19:48