Is it possible to test if a constexpr function is evaluated at compile time?

I think the canonical way to do that is with static_assert. static_asserts are evaluated at compile time, so they will break the build if their condition is false.

#include <iostream>

constexpr int foo(const int s) {
  return s + 4;
}

int main()
{
    std::cout << foo(3) << std::endl;
    const int bar = 3;
    std::cout << foo(bar) << std::endl;
    constexpr int a = 3;
    std::cout << foo(a) << std::endl;

    static_assert(foo(3) == 7, "Literal failed");
    static_assert(foo(bar) == 7, "const int failed");
    static_assert(foo(a) == 7, "constexpr int failed");
    return 0;
}

clang++ -std=c++14 so1.cpp compiles fine for me, showing that everything works as expected.


If you can use C++20, there is std::is_constant_evaluated which does exactly what you want. std::is_constant_evaluated is typically implemented using a compiler intrinsic.

This is called __builtin_is_constant_evaluated in GCC and clang, so you can implement your own "safe" wrapper around it, even in C++17 and lower.

// if C++20, we will need a <type_traits> include for std::is_constant_evaluated

#if __cplusplus >= 202002L
#include <type_traits>
#endif

constexpr bool is_constant_evaluated() {
#if __cplusplus >= 202002L
    return std::is_constant_evaluated();
#elif defined(__GNUC__) // defined for both GCC and clang
    return __builtin_is_constant_evaluated();
#else
    // If the builtin is not available, return a pessimistic result.
    // This way callers will implement everything in a constexpr way.
    return true;
#endif
}

Note that this builtin is still relatively new (GCC 9.0+) so you might also want to detect the compiler version.


The technique listed works, but since it uses static_assert it is not sfinae friendly. A better way (in theory, you'll see what I mean) to do this is to check whether a function is noexcept. Why? Because, constant expressions are always noexcept, even if the functions are not marked as such. So, consider the following code:

template <class T>
constexpr void test_helper(T&&) {}

#define IS_CONSTEXPR(...) noexcept(test_helper(__VA_ARGS__))

test_helper is constexpr, so it will be a constant expression as long as its argument is. If it's a constant expression, it will be noexcept, but otherwise it won't be (since it isn't marked as such).

So now let's define this:

double bar(double x) { return x; }

constexpr double foo(double x, bool b) {
    if (b) return x; 
    else return bar(x);
}

foo is only noexcept if the x is a constant expression, and b is true; if the boolean is false then we call a non constexpr function, ruining our constexpr-ness. So, let's test this:

double d = 0.0;

constexpr auto x = IS_CONSTEXPR(foo(3.0, true));
constexpr auto y = IS_CONSTEXPR(foo(3.0, false));
constexpr auto z = IS_CONSTEXPR(foo(d, true));

std::cerr << x << y << z;

It compiles, great! This gives us compile time booleans (not compile failures), which can be used for sfinae, for example.

The catch? Well, clang has a multi-year bug, and doesn't handle this correctly. gcc however, does. Live example: http://coliru.stacked-crooked.com/a/e7b037932c358149. It prints "100", as it should.


C++20 introduces is_constant_evaluated, defined in header <type_traits>, which addresses this issue.

constexpr int foo(int s)
{
    if (std::is_constant_evaluated()) // note: not "if constexpr"
        /* evaluated at compile time */;
    else
        /* evaluated at run time */;
}

Note that here the ordinary if is used instead of if constexpr. If you use if constexpr, then the condition has to be evaluated at compile time, so is_constant_evaluated always returns true, rendering the test useless.