Ch7.6: consteval

Overview

A consteval function must always be evaluated at compile time. It cannot run at runtime. If the compiler cannot evaluate the function during compilation, the program fails to compile.

This is stricter than constexpr. In practice, consteval is rarely needed, but it is useful when you want to guarantee that a function is never executed at runtime.

1. Basic example

A consteval function must be called in a constant expression.


#include 

consteval int double_value(int x)
{
    return x * 2;
}

int main()
{
    using namespace ::fast_io::iomnp;

    constexpr int a = double_value(10);  // OK: compile-time
    print("a = ", a, "\n");

    // int b = double_value(10);        // ERROR: cannot call at runtime
}

The second call fails because double_value cannot run at runtime.

2. Why this is rarely useful

Most functions do not need to be restricted to compile‑time evaluation. constexpr already allows compile‑time evaluation when needed, while still permitting runtime execution.

consteval is only useful when:

These situations are uncommon in normal application code.

3. Compile‑time validation

A consteval function can enforce constraints that must be checked during compilation.


#include 

consteval int positive(int x)
{
    if(x <= 0)
        throw "value must be positive";

    return x;
}

int main()
{
    using namespace ::fast_io::iomnp;

    constexpr int a = positive(5);   // OK
    print("a = ", a, "\n");

    // constexpr int b = positive(-3); // compile-time error
}

Any invalid input causes a compile‑time failure.

4. Difference from constexpr

constexpr functions:

consteval functions:


constexpr int f(int x) { return x + 1; }   // flexible
consteval int g(int x) { return x + 1; }   // strict

g() can only be used in constant expressions.

5. Interaction with if consteval

if consteval detects whether a constexpr function is being evaluated at compile time. But a consteval function is always evaluated at compile time.


#include 

constexpr int compute(int x)
{
    using namespace ::fast_io::iomnp;

    if consteval
        print("compile-time path\n");
    else
        print("runtime path\n");

    return x * 3;
}

consteval int force_ct(int x)
{
    return compute(x);  // always compile-time
}

force_ct() guarantees that compute() takes the compile‑time branch.

Key takeaways