What does it mean to be constexpr complete?

Yesterday Stephan Lavavej announced on the Visual C++ blog that their compiler would be constexpr complete for the Visual Studio 2015 build that is released to manufacturing. While that sounds exciting – and it is – I don’t think many developers really know what that means and may make certain reasonable assumptions about what is achievable at compile time. Stephan alluded to a difference between the original goals and aspirations for constexpr in the earlier C++11 standard compared to what is found in the newer C++14 standard. So what does this mean?

The original notion of a generalized constant expression is careful to limit the definition to sufficiently simple functions. That meant that such functions could not contain local variables, iteration statements, or selection statements. Such restrictions quickly became onerous and were lifted in C++14. I’m not a language lawyer so I’ll just give you an illustration. Imagine I need to count the occurrences of some character within a string. I would naturally like to express this at compile time as follows:

static_assert(Count("a % b % c % d") == 3, "fail");

With Visual Studio 2015, I need to be careful to implement the Count constexpr function to avoid using any of the aforementioned constructs. This is a reasonably simple problem so it doesn’t take a great leap of the imagination to write a simple recursive function:

constexpr unsigned Count(char const * const string)
    return *string == '\0' ? 0 : (*string == '%') + Count(string + 1);

While this is a recursive function, the recursion happens at compile time. In fact, the compiler may choose to unroll or transform the implementation to avoid recursion. From what I can tell, the Visual C++ compiler does not attempt to transform this so if I have a very large string then it will hit the compiler’s call-depth limit. Fortunately, this can be avoided with a compiler option. On the other hand, recursion is clearly not ideal and writing such contrived expressions quickly becomes error prone to say the least. The C++14 definition of constexpr functions makes it possible to write this function with more of the C++ language at my disposal:

constexpr unsigned Count(char const * string)
    unsigned count = 0;

    for (; *string != '\0'; ++string)
        count += *string == '%';

    return count;

Notice that I’m able to manually transform the recursive function with an iteration statement and use a local variable to keep track of the count. I am even able to increment the pointer. While this is a simple example and there’s nothing wrong with the recursive example above (unless I have very large strings) it sure is handy to be able to have the expressive power of C++14 constexpr functions at my fingertips.

2 thoughts on “What does it mean to be constexpr complete?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s