Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

consteval function returning object with non-trivial constexpr destructor

C++20 will have the new consteval keyword and constexpr destructor if all goes well. Sadly no compiler that I know of implements consteval at this time. Will the following code be valid?

struct A {
  constexpr ~A() {}
};

consteval A f() {
    return A{};
}

void test() {
    A a;
    a = f(); // <-- here
}

The issue comes from the line I marked — the destructor of the temporary A returned by f need to be called. but it should be called at the end of the full expression. so outside of the immediate evaluation.

I didn't find any quotes from the consteval and constexpr destructor papers that explicitly forbid this, but I can't see how it could be correct.

Will the following code be valid in C++20? What should happen with this code?


Note:

In the consteval paper, this example is given. Here the consteval function is called outside of constant context.

consteval int sqr(int n) {
  return n*n;
}
constexpr int r = sqr(100);  // Okay.
int x = 100;
int r2 = sqr(x);  // Error: Call does not produce a constant.
like image 386
Tyker Avatar asked Oct 14 '19 18:10

Tyker


1 Answers

I think this code is fine.

The salient aspect of consteval is [expr.const]/12:

An expression or conversion is in an immediate function context if it is potentially evaluated and its innermost non-block scope is a function parameter scope of an immediate function. An expression or conversion is an immediate invocation if it is an explicit or implicit invocation of an immediate function and is not in an immediate function context. An immediate invocation shall be a constant expression.

In

void test() {
    A a;
    a = f(); // <-- here
}

f() is an immediate invocation (it is an explicit invocation of an immediate function that is not in an immediate function context). So the requirement is that f() has to be a constant expression.

Note: just f(), not a = f();, there is no requirement that the assignment operator here is a constant expression.

Everything that f() invokes is perfectly fine. All of A's special member functions are invocable during constant evaluation time. The result of f() is a permitted result of a constant expression ([expr.const]/10) likewise because it does not trigger any of the restrictions there either (A has no pointer or reference members, so trivially none of them refer to objects without static storage duration).

Ultimately, the question of constant evaluation boils down to going through all the list of restrictions and seeing if anything breaks. I don't think we violate any of the rules, so this should be fine.

like image 78
Barry Avatar answered Nov 02 '22 12:11

Barry