c++c++20constexprconstexpr-function

What are the conditions that `constexpr` will start a new constant expression context?


I asked a question in Why `constexpr` specifier is not allowed for non-empty `std::vector`? previously, after finding the answer, I have another question here.

I tested and found that it is valid to dynamically allocate memory in one constexpr function and free it in another constexpr function (via new and delete), so a constexpr subroutines does not introduce a new context:

constexpr int* bar() {
  return new int{2};
}

constexpr int foo() {
  auto ptr = bar();
  int val = *ptr;
  delete ptr;
  return val;
}

constexpr int i = foo();  // OK

Then I get another question, what are the conditions such that constexpr will start a new context?

In a constant expression context (like in a consteval function), why constexpr std::vector<int> will start a new constant expression context (which make it invalid to declare because the memory allocated through new will escape this context) while std::vector<int> does not allocate memory in a new constant expression context?

I am a new learner about constexpr and C++20, please point out if I get wrong assumptions or ask a wrong problem.


Solution

  • what are the conditions such that constexpr will start a new context?

    Being a constant expression.

    The initializer for a constexpr or constinit variable is a constant expression. The initializer for a template parameter is a constant expression. The expression in an if constexpr is a constant expression. These expressions begin constant expression contexts.

    Calling a constexpr function is not a constant expression. Calling a constexpr function while evaluating a constant expression happens within a constant expression context, but it is not a context by itself.

    Calling a consteval function is not itself a constant expression context, but you're not allowed to call one unless you're already within a constant expression context.