CodeNebula
C++20coreadvanced

std::is_constant_evaluated (C++20 Addition)

C++20 · The Big Four · Compiler flag: -std=c++20

Explanation

Checks if code is evaluated in a `constexpr` context.

Real-World Scenario

Optimize code paths for compile-time vs. runtime in a library.

Quick Snippet

snippet.cpp
#include <type_traits> if (std::is_constant_evaluated()) {}

Full Example

is_constant_evaluated.cpp
// CodeNebula - C++20 Example: std::is_constant_evaluated()
// Compile: g++ -std=c++20 -Wall -Wextra -o example is_constant_evaluated.cpp

// std::is_constant_evaluated() lets a constexpr function detect whether
// it is being evaluated at compile time or at runtime, enabling
// dual-path code: one optimized for compile time, one for runtime.

#include <iostream>
#include <type_traits>
#include <cmath>
#include <cstring>

// A constexpr function with dual paths
constexpr double my_power(double base, int exp) {
    if (std::is_constant_evaluated()) {
        // Compile-time path: manual loop (no std::pow available)
        double result = 1.0;
        for (int i = 0; i < exp; ++i)
            result *= base;
        return result;
    } else {
        // Runtime path: use the optimized library function
        return std::pow(base, exp);
    }
}

// Another example: string length with dual paths
constexpr std::size_t my_strlen(const char* s) {
    if (std::is_constant_evaluated()) {
        // Compile-time: manual counting
        std::size_t len = 0;
        while (s[len] != '\0') ++len;
        return len;
    } else {
        // Runtime: use optimized C library
        return std::strlen(s);
    }
}

// Demonstrating the detection in different contexts
constexpr int detect_context() {
    if (std::is_constant_evaluated()) {
        return 1;   // compile-time path
    } else {
        return 2;   // runtime path
    }
}

int main() {
    // --- Compile-time evaluation ---
    constexpr double ct_power = my_power(2.0, 10);
    std::cout << "Compile-time: my_power(2.0, 10) = " << ct_power << "\n";

    constexpr std::size_t ct_len = my_strlen("Hello");
    std::cout << "Compile-time: my_strlen(\"Hello\") = " << ct_len << "\n";

    // --- Runtime evaluation ---
    double base = 2.0;
    int exp = 10;
    double rt_power = my_power(base, exp);
    std::cout << "Runtime:      my_power(2.0, 10) = " << rt_power << "\n";

    const char* str = "Hello";
    std::size_t rt_len = my_strlen(str);
    std::cout << "Runtime:      my_strlen(\"Hello\") = " << rt_len << "\n";

    // --- Context detection ---
    constexpr int ct_val = detect_context();  // compile-time -> 1
    int rt_val = detect_context();            // runtime -> 2

    std::cout << "detect_context() at compile time: " << ct_val << "\n";
    std::cout << "detect_context() at runtime:      " << rt_val << "\n";

    // static_assert works because my_power is evaluated at compile time
    static_assert(my_power(3.0, 3) == 27.0, "3^3 should be 27");
    static_assert(my_strlen("C++20") == 5, "Length should be 5");

    std::cout << "All static_assert checks passed.\n";

    return 0;
}

// Expected output:
// Compile-time: my_power(2.0, 10) = 1024
// Compile-time: my_strlen("Hello") = 5
// Runtime:      my_power(2.0, 10) = 1024
// Runtime:      my_strlen("Hello") = 5
// detect_context() at compile time: 1
// detect_context() at runtime:      2
// All static_assert checks passed.
Run command
g++ -std=c++20 -Wall -Wextra -o example is_constant_evaluated.cpp