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
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
?).