This is an unofficial snapshot of the ISO/IEC JTC1 SC22 WG21 Core Issues List revision 115d. See http://www.open-std.org/jtc1/sc22/wg21/ for the official list.
2024-10-26
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.7.3 [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]].