How to use a constexpr std::string
With C++20 we got consexpr std::vector
and std::string
in the STL. An awesome feature, I think, from a technical standpoint. However, the initial joy often ends quickly once most people I met tried to use it. Why? Well, maybe you already explored what you can do with this new ability of std::string
and discovered that the most naive application, creating a string at compile-time and transferring the data into run-time, isn't supported. There was a proposal aiming to add this kind of support, but it didn't end up in the standard. That leaves us with a std::string
we can create at compile-time, but we must also destroy the string at compile-time. It doesn't sound so good anymore, right?
Let's accept the fact that we can have that thing only at compile time, and we want to do something sensible with the new feature. What can we do? Here is one example.
Do you own a mobile phone? I come from an age where SMS was not only very expensive but also a cool new feature. Back then, I had to write a decode and encode for the SMS payload. Also, back then, bandwidth was expensive, too, and SMS was only a debug element providers started making money with; the number of characters was limited. In fact, it was so limited that the PDU used a clever trick. It was meant to be only for ASCII-supported languages. With that limitation, we all know that such a character fits into a char
or 8-bit. However, looking more closely, only 7 of these 8 bits are used. The most significant bit is always 0. It is during these times that people start becoming creative. Let's use that 8th bit. How? Well, the 8th bit becomes the lowest bit from the following byte, which then carries the next two bits for the following byte and so forth. In the end, this encodes eight characters into 7 bytes. A brilliant save at the time.
Long story short, as I said in the beginning, I wrote such a decoder and encoder. For this post, let's only care about the decoder. I polished my well-aged code a bit, applying C++23 to it. Here is how the decode looks:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
|
Remember, this post is about constexpr std::string
. Let's focus on that instead of the decode
algorithm.
Looking at the function declaration, you can see decode
returns a std::string
and the function itself is constexpr
.
Sure, I agree; there are probably zero SMS you can decode during compile-time. Hmm, maybe there are. What about testing? You definitely want to test such an algorithm as well! We have unit tests for that. But
- they often run late
- they might not detect undefined behavior
Did I get your attention?
While we can't do as much as we want with a constexpr std::string
, one thing we can do is check whether it matches another string in a static_assert
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 |
|
I find that a valuable use case for a constexpr std::string
which has a lot of benefits.
Andreas