How to check that a function is constexpr

I’ve been implementing quite a few simple C++11 constexpr functions in my ail (Avid Insight Library) project. While writing unit tests alongside it, I quickly realised that it would be very helpful to have code which verifies that a constexpr function is actually being evaluated at compile-time. It turns out that it’s remarkably easy to do.

Using static assert

Static asserts are another handy feature introduced in C++11. They let you verify compile-time conditions, such as template parameters and data type sizes. Helpfully, you can call constexpr functions as part of their condition. Obviously, if the function cannot be evaluated at compile-time then attempting to do this will fail.

Here’s an example:

template <typename T_ty>
constexpr T_ty pi()
{
    return T_ty(3.141592653589793);
}
 
static_assert(
    pi<float>() == 0 || true,
    "Compile-time evaluation check."
);

This is the same pi() function from my previous post, but this time we’ve added a static_assert underneath. In practice, this assertion doesn’t need to be directly underneath. It could be anywhere at all as long as it’s able to call our function, and in fact I’d advise keeping it (or a duplicate of it) in a separate test project which is built and executed regularly.

In the event that pi() is not a valid constexpr function, an error will be reported within the static_assert, saying something like “expression did not evaluate to a constant”. You can test this by removing the constexpr from the function signature and compiling the code. Note that the assertion itself is not being triggered. Rather, an error is being reported because it’s trying (and failing) to call our function at compile-time.

The second half of the condition (|| true) is there to prevent the assertion from being triggered under any circumstances. This is because we’re not interested in testing result of the function here. Rather, we just want to test how it gets called.

Why do you need to check?

Normally, the compiler should give you an error message if you write code in a constexpr function which violates the restrictions, preventing it from being evaluated at compile-time. For example, having more than one statement (which isn’t permitted under C++11), or trying to call a non-constexpr function.

The assert isn’t there to guard against that situation. Rather, it’s there guard against human error by testing the assumption that it’s declared as constexpr. Imagine you’ve got a long-standing code base, and somewhere in the future somebody unwittingly deletes the constexpr keyword from the function signature. This could happen by mistake or out of ignorance, and it’s entirely possible that nobody would notice because the compiler has silently switched to runtime evaluation. A simple static assert in your regular test code could help catch the issue.

I’m sure this sounds like a ridiculous or far-fetched situation to some people, and in an ideal world it would be. Unfortunately though, mistakes happen, as do inexperienced and bad programmers!

Leave a Reply

Your email address will not be published. Required fields are marked *