Converting string to lowercase at compile time with c++14
Update: The code has been completely rewritten and this post is no longer a relevant explanation. The latest code can be found in this Gist with explanations in the comments.
With the addition of the constexpr keyword in c++11 it is possible to calculate the result of function calls on compile time. I knew that it was possible to e.g. count the brackets in a string, but I wanted to take things a little bit further, I wanted to change the string.
I failed at doing this about a year ago, but now that I just updated to gcc 5.2, I decided to give it another shot.
The first question that has to be answered is how to return the resulting string. On compile time we can’t use types like std::string or std::vector and the parameters can’t be changed. You could use std::initializer_list<char> as the return type which allows directly constructing an std::string from the lowercase string literal (edit: this was not actually working at compile time, see update).
But it is not that easy to check the code with static asserts. That is why I use an std::array<char, N> as return type in the code below which allows verifying every character at compile time.
The code consists of three functions: one that converts a single character, one helper function that makes the conversion of the string and finally the function that you have to call. It was easy to see that I needed to use a variadic template pack expansion to construct the return value in one line, but this was the thing that seemed impossible. How do you change an N-character string into N parameters? I found the answer when I came across the std::integer_sequence type that was added in c++14. The std::make_integer_sequence will create a sequence of which the first argument is the type and the other arguments are a sequence of numbers from 0 to N-1. That was all I needed to get the thing working.
The following code can be used to confirm that all the code runs on compile time:
Update (4 Aug 2015)
After some experimenting it seems like the method does not work well with std::initializer_list<char> and the std::array was only used for testing and isn’t that useful. So I looked for an alternative way to return the data. I basically wanted to return a raw array, but you of course can’t do that, so I had to use a simple wrapper instead and changed the return types of the functions to array_wrapper<N>.
The only problem is that no matter what my function returns, it is not as user-friendly as I hoped. The following line will always run entirely at runtime, instead of the to_lower function call being run at compile time.
In order to execute it on compile time the line must be split:
.arr that you have to add behind the returned value is of course also not the most user-friendly solution.
Update (14 Dec 2016)
I have created a new implementation which is a slightly more friendly, you don’t have to add
.arr after the result call anymore. The code however still requires 2 lines to be run at compile time, trying to turn it into a useful one-liner still causes everything to be called at runtime.
Update (16 Dec 2016)