2121#include < type_traits>
2222#include < functional>
2323#include < memory>
24+ #include < new> // std::launder
2425
2526// ----- SYNOPSIS -----
2627
@@ -68,6 +69,20 @@ class empty_delegate_error : public std::bad_function_call
6869 }
6970};
7071
72+ template <std::size_t Size, std::size_t Align>
73+ struct sbo_storage {
74+ alignas (Align) std::byte data[Size];
75+
76+ template <class T >
77+ constexpr T& as () noexcept {
78+ return *std::launder (reinterpret_cast <T*>(data));
79+ }
80+ template <class T >
81+ constexpr const T& as () const noexcept {
82+ return *std::launder (reinterpret_cast <const T*>(data));
83+ }
84+ };
85+
7186// ----- IMPLEMENTATION -----
7287
7388namespace detail
@@ -163,7 +178,7 @@ template<
163178> class inplace_triv
164179{
165180public:
166- using storage_t = std:: aligned_storage_t <size, align>;
181+ using storage_t = sbo_storage <size, align>;
167182 using invoke_ptr_t = R(*)(storage_t &, Args&&...);
168183
169184 explicit inplace_triv () noexcept :
@@ -178,7 +193,10 @@ template<
178193 > explicit inplace_triv (T&& closure) :
179194 invoke_ptr_{ static_cast <invoke_ptr_t >(
180195 [](storage_t & storage, Args&&... args) -> R
181- { return reinterpret_cast <C&>(storage)(std::forward<Args>(args)...); }
196+ {
197+ auto & closure = storage.template as <C>();
198+ return closure (std::forward<Args>(args)...);
199+ }
182200 )}
183201 {
184202 static_assert (sizeof (C) <= size,
@@ -211,12 +229,12 @@ template<
211229
212230 bool empty () const noexcept
213231 {
214- return reinterpret_cast <std::nullptr_t &>(storage_ ) == nullptr ;
232+ return storage_. template as <std::nullptr_t &>() == nullptr ;
215233 }
216234
217235 template <typename T> T* target () const noexcept
218236 {
219- return reinterpret_cast <T*>(&storage_ );
237+ return &storage_. template as <T*>();
220238 }
221239
222240private:
@@ -233,7 +251,7 @@ template<
233251> class inplace
234252{
235253public:
236- using storage_t = std:: aligned_storage_t <size, align>;
254+ using storage_t = sbo_storage <size, align>;
237255
238256 using invoke_ptr_t = R(*)(storage_t &, Args&&...);
239257 using copy_ptr_t = void (*)(storage_t &, storage_t &);
@@ -251,12 +269,18 @@ template<
251269 > explicit inplace (T&& closure) noexcept :
252270 invoke_ptr_{ static_cast <invoke_ptr_t >(
253271 [](storage_t & storage, Args&&... args) -> R
254- { return reinterpret_cast <C&>(storage)(std::forward<Args>(args)...); }
272+ {
273+ auto & closure = storage.template as <C>();
274+ return closure (std::forward<Args>(args)...);
275+ }
255276 ) },
256277 copy_ptr_{ copy_op<C, storage_t >() },
257278 destructor_ptr_{ static_cast <destructor_ptr_t >(
258279 [](storage_t & storage) noexcept -> void
259- { reinterpret_cast <C&>(storage).~C (); }
280+ {
281+ auto & closure = storage.template as <C>();
282+ closure.~C ();
283+ }
260284 ) }
261285 {
262286 static_assert (sizeof (C) <= size,
@@ -337,7 +361,7 @@ template<
337361
338362 template <typename T> T* target () const noexcept
339363 {
340- return reinterpret_cast <T*>(&storage_ );
364+ return &storage_. template as <T>( );
341365 }
342366
343367private:
@@ -357,7 +381,7 @@ template<
357381 {
358382 return [](S& dst, S& src) noexcept -> void
359383 {
360- new (&dst)T{ reinterpret_cast <T&>(src ) };
384+ new (&dst)T{ src. template as <T>( ) };
361385 };
362386 }
363387
0 commit comments