C++ Logo

std-proposals

Advanced search

Re: [std-proposals] std::typeless_memory (type punning)

From: Arthur O'Dwyer <arthur.j.odwyer_at_[hidden]>
Date: Sat, 30 Nov 2024 21:17:53 -0500
On Sat, Nov 30, 2024 at 6:42 PM James via Std-Proposals <
std-proposals_at_[hidden]> wrote:

> Hi, I mean a specific valid runtime code should be able to run at compile
> time. Nothing more. The following code is pretty much valid, but you can't
> do it in compile time:
> ```cpp
> alignas(alignof(T)) std::byte data[sizeof(T)];
> new(&data) T();
> std::launder(reinterpret_cast<T*>(&data))->~T();
> ```
>
> Compilers can detect overflow, memory leak, etc and don't allow it in
> compile time. I'd like to see a similar approach. Allow both placement new
> and reinterpret_cast, if usage is valid.
>

Read these two recent proposals, both already adopted for C++26:
- P2747 constexpr placement new
<https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2747r2.html>
(Revzin),
adopted for C++26; feature-test macro is __cpp_lib_constexpr_new
- P2738 constexpr cast from void*
<https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2738r1.pdf>
(Jabot, Ledger), adopted for C++26: feature-test macro is (__cpp_constexpr
== 202306L)

The former seems to be exactly what you're asking for
with constexpr `::new (p) T(...)`.
The latter seems to be *almost* exactly what you're asking for with
constexpr `reinterpret_cast<T*>(p)`, except that you are required to spell
it `static_cast<T*>(static_cast<void*>(p))` instead of using the
`reinterpret_cast` operator itself.

My initial understanding was that these proposals would make this legal in
C++26—
https://godbolt.org/z/bbdGaMv4e

template<class T>
constexpr T f() {
alignas(alignof(T)) char data[sizeof(T)];
T *p = ::new (data) T();
T t = *p;
p->~T();
return t;
}
static_assert(f<std::string>() == "");

—but both Clang and GCC claim to have implemented them, and neither Clang
nor GCC accepts this code.

Both Clang and GCC accept this `union`-based code, though:
https://godbolt.org/z/frhjh9nEx

template<class T>
constexpr T f() {
union U {
constexpr U() {}
constexpr ~U() {}
char c_;
T t_;
} data;
T *p = ::new (&data.t_) T();
T t = *p;
p->~T();
return t;
}
static_assert(f<std::string>() == "");

GCC (but not Clang) even accepts this:
https://godbolt.org/z/fqxnfM6eo

template<class T>
constexpr T f() {
union U {
constexpr U() {}
constexpr ~U() {}
char c_;
T t_;
} data;
T *p = ::new (&data) T();
T t = *p;
p->~T();
return t;
}
static_assert(f<std::string>() == "");

HTH,
Arthur

Received on 2024-12-01 02:18:11