5

I want to check whether a function can be evaluated during compilation. I found this, but I don't understand the concept completely. I have a few doubts:

  1. What is the role of the following line in the code?
    template<int Value = Trait::f()>

  2. Every time when I need to check whether the function is compile-time evaluable, Do I need to make it a member function of some struct?

PS
I am copying the code in the link, just for convenience.

template<typename Trait>
struct test
{
    template<int Value = Trait::f()>
    static std::true_type do_call(int){ return std::true_type(); }

    static std::false_type do_call(...){ return std::false_type(); }

    static bool call(){ return do_call(0); }
};

struct trait
{
    static int f(){ return 15; }
};

struct ctrait
{
    static constexpr int f(){ return 20; }
};

int main()
{
   std::cout << "regular: " << test<trait>::call() << std::endl;
   std::cout << "constexpr: " << test<ctrait>::call() << std::endl;
}
zeroset
  • 55
  • 5
  • 4
    In the grand scheme of things, there are far, far more useless questions that get constantly posted here, so here's an upvote, to counter-balance the downvote. Don't pay too much attention to stray downvotes, they're just collateral damage... – Sam Varshavchik Aug 19 '20 at 02:04
  • 2
    `template` effectively requires that `Trait::f()` can be evaluated at compile time. If it cannot be, this overload does not participate in overload resolution. If it is present, it is the best match for `do_call(0);` but if it is eliminated then `do_call(...)` becomes the best match. – cdhowie Aug 19 '20 at 02:19
  • Additional issue is that `constexpr` functions might only be used in constant expression for a given subset of possible parameters. so `f(0)` is not valid whereas `f(42)` is (`constexpr int f(int i) { if (i == 0) throw std::runtime_error(".."); return i;}`. – Jarod42 Aug 19 '20 at 07:32

1 Answers1

2

Here is just a quick example of what you can get with std::void_t to tackle your point 2 that can be generic in some way...

#include <iostream>
#include <type_traits>

int f() {
    return 666;
}

constexpr int cf(int, double) {
    return 999;
}

template <auto F>
struct indirection {
};

template<typename F, class = std::void_t<> >
struct is_constexpr : std::false_type { };

template<typename F, typename... Args>
struct is_constexpr<F(Args...),
           std::void_t<indirection<F(Args{}...)>>
       > : std::true_type { };

int main()
{
   std::cout << is_constexpr<decltype(f)>::value << std::endl;
   std::cout << is_constexpr<decltype(cf)>::value << std::endl;
};

Demo here

Jarod42
  • 203,559
  • 14
  • 181
  • 302
nop666
  • 585
  • 2
  • 6