Created on 2022-03-05.00:00:00 last changed 44 months ago
7.7 [expr.const] paragraph 6 specifies that std::construct_at can be used during constant evaluation:
Similarly, the evaluation of a call to std::construct_at or std::ranges::construct_at does not disqualify E from being a core constant expression unless the first argument, of type T*, does not point to storage allocated with std::allocator<T> or to an object whose lifetime began within the evaluation of E, or the evaluation of the underlying constructor call disqualifies E from being a core constant expression.
Apparently, implementations are required to track whether an object is transparently replaceable (6.8.4 [basic.life] paragraph 8) during constant evaluation to satisfy 7.7 [expr.const] bullet 5.8, which requires that undefined behavior be detected and rejected during constant evaluation:
- ...
- an operation that would have undefined behavior as specified in Clause 4 through Clause 15;
- ...
For example,
struct A {
int x, y;
};
struct B {
float a;
int b;
};
union C {
A a;
B b;
};
constexpr int f() {
C c = {};
std::construct_at(&c.b.b, 5);
// Does this return 5 if c.a.y and c.b.b are laid out at the same address?
return c.a.y;
}
static_assert(f()); // not a constant-expression
No known implementation diagnoses the violation of the rules for transparently replaceable in the following example, but there is implementation divergence for the results of f():
#include <memory>
struct A {
virtual constexpr char f() { return 'A'; }
};
struct B : A {
constexpr char f() override { return 'B'; }
};
constexpr char f() {
B b;
A *p = &b;
std::construct_at(p);
return p->f(); // #1; alternative: return b.f()
}
static_assert(f() == 'A'); // error: #1 accesses out-of-lifetime object
See also issue 2866 for concerns about observing the effects of an attribute if the potentially-overlapping subobject was introduced via [[no_unique_address]].
| History | |||
|---|---|---|---|
| Date | User | Action | Args |
| 2022-03-05 00:00:00 | admin | create | |