But constexpr-ness of bit_cast has additional limitations and e.g. providing an union as _Tp would be a hard-error. So we have two options: - before bitcasting check if type can be bitcast-ed at compile-time, - change the 'if constexpr' to regular 'if'.
If we go with the second solution then we will include classes with pointers, and unions. Additionally we could also include types with padding by passing zero-initialized object (like a class-scope static constexpr or global) into bit_cast... but then such a variable would be ODR-used and most-likely won't be optimized out. I guess the best option would be to introduce in C++ language a new compiler-backed type trait like: std::zero_initialized_object_has_all_zeros_object_representation<T>. Regards, Maciej pt., 28 cze 2024 o 00:25 Jonathan Wakely <jwak...@redhat.com> napisaĆ(a): > On Thu, 27 Jun 2024 at 14:27, Maciej Cencora <m.cenc...@gmail.com> wrote: > > > > I think going the bit_cast way would be the best because it enables the > optimization for many more classes including common wrappers like optional, > variant, pair, tuple and std::array. > > This isn't tested but seems to work on simple cases. But for large > objects the loop hits the constexpr iteration limit and compilation > fails, so it needs a sizeof(_Tp) < 64 or something. > > using _ValueType > = typename iterator_traits<_ForwardIterator>::value_type; > using _Tp = remove_all_extents_t<_ValueType>; > // Need value-init to be equivalent to zero-init. > if constexpr (is_member_pointer<_Tp>::value) > return nullptr; > else if constexpr (!is_scalar<_Tp>::value) > { > using __trivial > = __and_<is_trivial<_ValueType>, > is_trivially_constructible<_ValueType>>; > if constexpr (__trivial::value) > { > struct _Bytes > { > unsigned char __b[sizeof(_Tp)]; > > #if __cpp_constexpr >= 201304 > constexpr bool _M_nonzero() const > { > for (auto __c : __b) > if (__c) > return true; > return false; > } > #else > constexpr bool _M_nonzero(size_t __n = 0) const > { > return __n < sizeof(_Tp) > && (__b[__n] || _M_nonzero(__n + 1)); > } > #endif > }; > if constexpr (__builtin_bit_cast(_Bytes, _Tp())._M_nonzero()) > return nullptr; > } > } > using _Ptr = decltype(std::__to_address(__first)); > // Cannot use memset if _Ptr is cv-qualified. > if constexpr (is_convertible<_Ptr, void*>::value) > return std::__to_address(__first); > >