2

Any type_traits or method could find out the parameters is a constexpr or not?

Example

size_t fibo_runtime(size_t num)
{
  //implementation
}

constexpr size_t fibo(size_t num)
{
    return is_constexpr<size_t>::value ? //this type traits looks weird and unreasonable
           (num > 1 ? fibo(num - 1) * num : 1) :
           fibo_runtime(num);
}

constexpr could apply on constexpr parameter and the parameter be determined at run time. However, recursive may not efficient enough on runtime.

Do we have anyway to separate the implementation of runtime and compile time of constexpr functions? if we could not do that, could we enforce the users could not use the constexpr function to do some runtime evaluation?

BenMorel
  • 34,448
  • 50
  • 182
  • 322
StereoMatching
  • 4,971
  • 6
  • 38
  • 70
  • 2
    Anything you can do with templates has to work at compile time. So the "trait" is "will it compile?". – Kerrek SB Mar 05 '13 at 23:16
  • I don't know, it is just a concept of what kind of effect I would like to have. I want to figure out the "num" is a constexpr or not on compile time, but I don't know how to do it or this is possible or not? – StereoMatching Mar 05 '13 at 23:24

3 Answers3

0

The very nature of constant expression (constexpr) is to be constant. So runtime evaluation or not, they will not change any of their behavior and the evaluation will never be done at runtime.

If you use a constexpr function at runtime (which is not simply by calling it straightforwardly), then it will be called as a normal function, as the expression cannot be resolved by nature as constant during runtime.

If you want to achieve some different implementation depending on compile-time or runtime it will (if you achieve it) be really disturbing for the developer as the function would not have the same behavior depending on how you call it ! Thus it becomes clear that such behavior could not / will not / should not be implemented.

If you want to specialize a function for compile-time computation, use a different function to clearly state your intentions.

Jaffa
  • 12,442
  • 4
  • 49
  • 101
  • 2
    We use different algorithms side-by-side that do technically same thing (for example sorting) because of differences in performance in different situations. There are no silver bullet solutions for all situations. When we have different performance requirements depending if something is done compile-time or run-time then it makes perfect sense to detect that and to use different algorithms. – Öö Tiib Jan 27 '16 at 16:49
  • Thanks for your point of view, and you're right, but I still think it could be confusing for the devs – Jaffa Jan 29 '16 at 10:26
0

Within the function, it isn't possible to check the parameters to see if the complete calling expression is a constant expression. But you can implement a macro at the call site to test the same thing, evaluating to true_type or false_type at compile time depending on whether the expression is a constant expression

IS_A_CONSTANT_EXPRESSION(  fibo(5)          )    // is constant
IS_A_CONSTANT_EXPRESSION(  fibo(time(NULL)  )    // is not constant

The details are in this answer to another question. (My own answer, apologies for cross posting!)

You could then implement another macro, FIBO( expr ) to wrap this up nicely and call the correct version as appropriate.

Community
  • 1
  • 1
Aaron McDaid
  • 26,501
  • 9
  • 66
  • 88
-3

I think this may get you what you want

#include <iostream>

template <typename T>
class is_constexpr
{
   typedef char true_type ;
   struct false_type { true_type _[2] ; } ;

   template <typename U>
   static true_type has_constexpr( U & ) ;

   template <typename U>
   static false_type has_constexpr(...) ;

   public:
      enum { value = ( sizeof(has_constexpr<T>(0)) == sizeof(true_type)) } ;
} ;

int main()
{
   constexpr int i = 10 ;
   int k = 20 ;

   std::cout << is_constexpr<decltype(i)>::value << std::endl ;
   std::cout << is_constexpr<decltype(k)>::value << std::endl ;   
}

I used Understanding SFINAE as a reference.

Doing some more research I think I the answer to the other part of the question is yes, since it looks a constexpr function template is not always usable in a constant expression. So this leads to a solution like so, with this somewhat contrived example:

template <typename T>
T f2( T num )
{ 
   return num + 1;
}

template <typename T>
constexpr T f1( T num )
{
   return num ;
}

template <typename T>
constexpr T f(T num)
{
   return  is_constexpr<T>::value ? f1(num) : f2(num) ;
} 
Community
  • 1
  • 1
Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
  • I was able to make your last code work but only if I pass T&&, for example in the simplified `template constexpr bool f(T&& num){return is_constexpr::value;}` [`gcc 4.8.2`] – alfC Jan 23 '14 at 19:41
  • And even then I am puzzled why literals are not `constexpr` like (`f(5)`) – alfC Jan 23 '14 at 19:48
  • 5
    -1 This answer is wrong since 'is_constexpr' does not detect that T is constant expression but merely if it is const. That can be easily found out by adding 'const int m = argc;' that also results with being "constexpr" that runtime argument count can not be. – Öö Tiib Jan 27 '16 at 12:09
  • 2
    I agree with @ÖöTiib, it only checks if the type is const, not constexpr. In C++11 or later, you could more easily just do `std::is_const::value`, from `type_traits`. – hadriel Oct 15 '16 at 14:25
  • Hello Shafik. You might want to delete this answer ;) – YSC Jul 23 '19 at 08:27