Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++20 Constexpr vector

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

like image 598
getsoubl Avatar asked Mar 31 '26 13:03

getsoubl


1 Answers

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

like image 129
Barry Avatar answered Apr 03 '26 05:04

Barry



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!