26

Many developers and library authors have been struggling with compile-time strings for quite a few years now - as the standard (library) string, std::string, requires dynamic memory allocation, and isn't constexpr.

So we have a bunch of questions and blog posts about how to get compile-time strings right:

We've now learned that not only is new available in constexpr code, allowing for dynamical allocation at compile-time, but, in fact, std::string will become constexpr in C++20 (C++ standard working group meeting report by Herb Sutter).

Does that mean that for C++20-and-up code we should chuck all of those nifty compile-time string implementations and just always go with std::string?

If not - when would we do so, and when would we stick to what's possible today (other than backwards-compatible code of course)?


Note: I'm not talking about strings whose contents is part of their type, i.e. not talking about the equivalent of std::integral_constant; that's definitely not going to be std::string.

einpoklum
  • 118,144
  • 57
  • 340
  • 684
  • Have you answered your own question or am I missing something? – Havenard Jul 20 '19 at 23:22
  • Do note that there's a big difference between a `constexpr` string and a string whose data is *part of its type*. The latter allows you to take a string that is not a constant expression (e.g., a parameter) and extract the data as a constant expression. This is what you see with the plethora of TMP in the string definition. `constexpr` strings have always been an option, but you simply could never take a constexpr string parameter and use its data as a template argument or similar. What has changed here is that `consteval` is also in C++20, but is not mentioned anywhere in your question. – chris Jul 20 '19 at 23:45
  • One other consideration I'll leave: `ctre::match<"REGEX">(subject);` – chris Jul 21 '19 at 00:01
  • "_dynamical allocation at compile-time_" - hmm, I'm not sure that's an accurate statement. – Marc.2377 Jul 21 '19 at 02:37
  • `fmt` library currently uses constexpr "strings" to perform compile-time type checking of arguments – M.M Jul 21 '19 at 02:39
  • 2
    @Marc.2377: Dynamic in the sense that the amount of memory to allocate is not known by considering solely the function in which the allocation occurs. Or if you will - dynamic in the sense of using `new` and `delete`. – einpoklum Jul 21 '19 at 11:42

1 Answers1

24

It depends on what you mean by "constexpr string".

What C++20 allows you to do is to use std::string within a function marked constexpr (or consteval). Such a function can create a string, manipulate it, and so forth just like any literal type. However, that string cannot leak out into non-constexpr code; that would be a non-transient allocation and is forbidden.

The thing is, all of the examples you give are attempts to use strings as template parameters. That's a similar-yet-different thing. You're not just talking about building a string at compile-time; you now want to use it to instantiate a template.

C++20 solves this problem by allowing user-defined types to be template parameters. But the requirements on such types are much more strict than merely being literal types. The type must have no non-public data members and the only members are of types that follow those restrictions. Basically, the compiler needs to know that a byte-wise comparison of its data members represents an equivalent value. And even a constexpr-capable std::string doesn't work that way.

But std::array<char, N> can do that. And if you are in constexpr code, call a constexpr function which returns a std::string, and store that string in a constexpr value, then string::size() is a constexpr function. So you can use that to fill in the N for your array.

Copying the characters into a constexpr array (since it's a constexpr value, it's immutable) is a bit more involved, but it's doable.

So C++20 solves those problem, just not (directly) with std::string.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982