On Fri, 28 Jun 2024 at 07:53, Maciej Cencora <m.cenc...@gmail.com> wrote: > > 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.
I don't think we want to add runtime comparisons, the point is to optimize the code not do more work :-) > 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>. Yes, I think a new built-in is the only approach that will work for class types. I'll just limit the optimization to scalars (excluding member pointers). > > 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); >>