The latest C++20 standard supports dynamic allocation memory in compile time with a limitation. The memory allocation cannot "go outside" the constant expression. That means that vector cannot be return and stored in a constexpr variable.
In the cppstories article there is the following example
#include <vector>
#include <string>
#include <algorithm>
constexpr std::vector<std::string>
split(std::string_view strv, std::string_view delims = " ") {
std::vector<std::string> output;
size_t first = 0;
while (first < strv.size()) {
const auto second = strv.find_first_of(delims, first);
if (first != second)
output.emplace_back(strv.substr(first, second-first));
if (second == std::string_view::npos)
break;
first = second + 1;
}
return output;
}
constexpr size_t numWords(std::string_view str) {
const auto words = split(str);
return words.size();
}
int main() {
static_assert(numWords("hello world abc xyz") == 4);
}
This example compiles successfully. If I change
const auto words = split(str);
to
constexpr auto words = split(str);
I get following error
example.cpp (27): error C2131: expression did not evaluate to a constant (27): note: failure was caused by a read of a variable outside its lifetime (27): note: see usage of 'str' Compiler returned: 2
Based on the standard this expected since the compilers don’t support so-called "non-transient" memory allocations. But why no error is reported when const is used. In bot cases the code is executed in compile time
2 Answers 2
This has nothing to do with allocation.
When you attempted to write
constexpr auto words = split(str);
Declaring a constexpr variable starts a new constant evaluation. Yes, we happen to be inside of one already (the outer static_assert call), but declaring a constexpr variable (or initializing a constant template argument or the condition of an if constexpr or ...) start a new.
Each new constant evaluation has to be complete in of itself. Here, we don't know what str is. We didn't see its initialization. So we cannot evaluate this as a constant. That's the error:
note: failure was caused by a read of a variable outside its lifetime
note: see usage of 'str'
This is the same issue as you'd see in this example:
constexpr int plus_one(int x) {
const int y = x + 1;
return y;
}
static_assert(plus_one(4) == 5);
If you change the declaration of y to be constexpr instead of const, this also wouldn't compile anymore (because: what is x?).
Comments
You're correct, c++ 20 does allows dynamic memory in constexpr but only within the expression's scope.
constexpr auto words = split(str);
When you use the const, it runs at compile-time because of the static_assert, but the result doesn't need to be in constexpr .
This fails because it tries to extend the lifetime of str, which is not allowed in the constant expressions due to standard rules .
And const doesn't set of the stick check, so no get's no error there.
Comments
Explore related questions
See similar questions with these tags.
constis not needed in this context: godbolt.org/z/65Pq1z9hW