Detecting Compile-time vs Runtime in C++: if consteval vs std::is_constant_evaluated()


C++ has been steadily adding features to let programmers distinguish code that runs at compile time from code that runs at runtime. Two important tools for this are the function std::is_constant_evaluated() (C++20) and the language-level if consteval (C++23). This post explains both, shows practical examples, compares their guarantees and trade-offs, and suggests when to use each.

Both techniques let you write branches that behave differently depending on whether evaluation happens in a constant-evaluation (compile-time) context or at runtime. The differences are subtle but important: one is a function returning a boolean, the other is a special if that the compiler treats as a compile-time-only branch check.

std::is_constant_evaluated() (C++20)

This is a function declared in <type_traits>:

#include <type_traits> 
constexpr bool std::is_constant_evaluated() noexcept;

It returns true when the current expression is being evaluated in a constant-expr (compile-time) context, and false otherwise.

Example:

#include <iostream> 
#include <type_traits> 

constexpr int f() { 
    if (std::is_constant_evaluated()) { 
        return 42; // compile-time 
    } else { 
        return 0; // runtime 
    } 
} 

int main() { 
    constexpr int a = f(); // evaluated at compile time -> 42
    int b = f(); // evaluated at runtime -> 0 
    std::cout << a << ", " << b << "\n"; // prints "42, 0" 
}

if consteval (C++23)

if consteval is a language-level if that the compiler uses to determine whether the current evaluation context is a constant evaluation. It provides stronger compile-time guarantees: the compiler knows the consteval branch must be usable in constant evaluation and will reject code that cannot appear in that context.

Syntax:

if consteval { 
    // compile-time-only code 
} else { 
    // runtime-only code 
} 

Example:

#include <iostream> 

constexpr int f() { 
    if consteval { 
        return 42; // compile-time version 
    } else { 
        return 0; // runtime version 
    } 
} 

int main() { 
    constexpr int a = f(); // compile-time context -> returns 42 
    int b = f(); // runtime context -> returns 0 
    std::cout << a << ", " << b << "\n"; // prints "42, 0" 
}

Key differences (summary)

  • Form: std::is_constant_evaluated() is a function; if consteval is a language-level conditional.
  • Standard: std::is_constant_evaluated() arrived in C++20; if consteval arrived in C++23.
  • Guarantees: if consteval gives the compiler compile-time guarantees and rejects code in the consteval branch that cannot be used at compile time. std::is_constant_evaluated() is more permissive: it returns a boolean but does not force the compiler to reject invalid compile-time-only constructs in the other branch.
  • Use inside expressions: std::is_constant_evaluated() can be used inside expressions where a statement-form if cannot (e.g., inside a ternary operator). if consteval requires a statement-level context.

Concrete comparison example

Two functions that appear similar but behave differently in terms of enforcement:

// if-consteval example 
constexpr int f() { 
    if consteval { 
        return 1; // compile-time only 
    } else { 
        return 2; // runtime only 
    } 
} 

// std::is_constant_evaluated() example 
#include <type_traits> 
constexpr int g() { 
    if (std::is_constant_evaluated()) { 
        return 1; // may still compile runtime path 
    } else { 
        return 2; 
    } 
}

A scenario where the difference matters:

// With if consteval the compiler will reject invalid compile-time-only constructs
constexpr int bad() {
    if consteval {
        std::cout << "compile-time";  // ❌ error — I/O is not allowed in constant evaluation
    }
    return 0;
}

// With std::is_constant_evaluated(), the compiler is more permissive and may compile until the code
// is actually used in a constant expression context.
#include <type_traits>
constexpr int maybe_bad() {
    if (std::is_constant_evaluated()) {
        std::cout << "compile-time";  // may compile; error surfaces only when evaluated in a const-expr
    }
    return 0;
}

When to use which

  • If you target C++23 (or later) and want clear, compile-time-enforced branching: prefer if consteval.
  • If you must support only C++20 environments: use std::is_constant_evaluated().
  • If you need the check within an expression (not a statement), use std::is_constant_evaluated() because if consteval is statement-level.
  • If you want the compiler to reject code that cannot be used at compile time, if consteval provides stronger guarantees.

Practical use cases

  • Write different implementations for compile-time vs runtime (fast precomputation vs slower runtime logic).
  • Guard runtime-only operations (like I/O, dynamic allocations, or system calls) so they are not accidentally used in a constant-evaluation path.
  • Provide clearer, intention-revealing code when authoring libraries that may be used in both constexpr contexts and normal runtime contexts.

Short, practical checklist

  • Need expression-level check? → std::is_constant_evaluated().
  • Want compiler-enforced compile-time-only branch? → if consteval.
  • Targeting C++20 only? → std::is_constant_evaluated().
  • Targeting C++23+ and prefer clarity & safety? → if consteval.

TL;DR

std::is_constant_evaluated() — C++20: function that returns true inside compile-time evaluation (good for expression-level checks).

if consteval — C++23:

  • language-level conditional that the compiler treats as a compile-time-only branch;
  • stronger compile-time enforcement and clearer intent.

Closing notes

Both tools are useful. If you can use C++23, prefer if consteval for clearer semantics and stronger compile-time guarantees, and fall back to std::is_constant_evaluated() for compatibility with C++20 or when you need expression-level checks.

C/C++ Programming

–EOF (The Ultimate Computing & Technology Blog) —

1056 words
Last Post: Teaching Kids Programming - Two Ways to Prove Square Root of Two is Irrational (proof by contradiction and geometric infinite descent)
Next Post: Alpha Arena: How AI Performs in the Real Crypto Market

The Permanent URL is: Detecting Compile-time vs Runtime in C++: if consteval vs std::is_constant_evaluated() (AMP Version)

Leave a Reply