Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What are the advantages of using consteval instead of constexpr function?

I know the difference in requirements, I am mostly interested in what benefits from code quality it brings.

Few things I can think of:

  • reader can just read the function signature and know that function is evaluated at compile time
  • compiler may emit less code since consteval fns are never used at runtime(this is speculative, I have no real data on this)
  • no need to have variables to force ctfe, example at the end

note: if code quality is too vague I understand some people might want to close this question, for me code quality is not really that vague term, but...

example where constexpr failure is delayed to runtime:

constexpr int div_cx(int a, int b)
{ 
  assert(b!=0);
  return a/b;
}
    
int main()
{
    static constexpr int result = div_cx(5,0); // compile time error, div by 0
    std::cout << result; 
    std::cout << div_cx(5,0) ; // runtime error :( 
}
like image 606
NoSenseEtAl Avatar asked Dec 10 '22 00:12

NoSenseEtAl


1 Answers

In order to have meaningful, significant static reflection (reflection at compile time), you need a way to execute code at compile time. The initial static reflection TS proposal used traditional template metaprogramming techniques, because those were the only effective tools for executing code at compile-time at all.

However, as constexpr code gained more features, it became increasingly more feasible to do compile-time static reflection through constexpr functions. One problem with such ideas is that static reflection values cannot be allowed to leak out into non-compile-time code.

We need to be able to write code that must only be executed at compile-time. It's easy enough to do that for small bits of code in the middle of a function; the runtime version of that code simply won't contain the reflection parts, only the results of them.

But what if you want to write a function that takes a reflection value and returns a reflection value? Or a list of reflection values?

That function cannot be constexpr, because a constexpr function must be able to be executed at runtime. You are allowed to do things like get pointers to constexpr functions and call them in ways that the compiler can't trace, thus forcing it to execute at runtime.

A function which takes a reflection value can't do that. It must execute only at compile-time. So constexpr is inappropriate for such functions.

Enter consteval: a function which is "required" to execute only at compile time. There are specific rules in place that make it impossible for pointers to such functions to leak out into runtime code and so forth.

As such, consteval doesn't have much purpose at the moment. It gets used in a few places like source_location::current(), which fundamentally makes no sense to execute at runtime. But ultimately, the feature is a necessary building-block for further compile-time programming tools that don't exist yet.

This was laid down in the paper that originally proposed this feature:

The impetus for the present paper, however, is the work being done by SG7 in the realm of compile-time reflection. There is now general agreement that future language support for reflection should use constexpr functions, but since "reflection functions" typically have to be evaluated at compile time, they will in fact likely be immediate functions.

like image 95
Nicol Bolas Avatar answered Jan 11 '23 23:01

Nicol Bolas