On Fri, 30 Apr 2021, Tim Song wrote: > On Fri, Apr 30, 2021 at 12:11 PM Patrick Palka via Libstdc++ > <libstd...@gcc.gnu.org> wrote: > > > > + template<typename _Iter> > > + _Tp& > > + _M_emplace_deref(const _Iter& __i) > > + { > > + this->reset(); > > + return this->emplace(*__i); > > + } > > This incurs a move, avoiding of which is the sole reason for > emplace-deref's existence.
Ah thanks, I had missed that... IIUC, if we instead derive from optional's internal base class _Optional_base, we can easily get at the underlying storage for the object and directly initialize it with '*__i' and avoid the move. How does the the following adjustment to the patch look? -- >8 -- diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges index 971898f5492..f1db4a238ef 100644 --- a/libstdc++-v3/include/std/ranges +++ b/libstdc++-v3/include/std/ranges @@ -2254,7 +2254,7 @@ namespace views::__adaptor template<typename _Tp> requires is_object_v<_Tp> - struct __non_propagating_cache<_Tp> : private optional<_Tp> + struct __non_propagating_cache<_Tp> : private _Optional_base<_Tp> { __non_propagating_cache() = default; @@ -2264,32 +2264,36 @@ namespace views::__adaptor constexpr __non_propagating_cache(__non_propagating_cache&& __other) noexcept - { __other.reset(); } + { __other._M_reset(); } constexpr __non_propagating_cache& operator=(const __non_propagating_cache& __other) noexcept { if (std::__addressof(__other) != this) - this->reset(); + this->_M_reset(); return *this; } constexpr __non_propagating_cache& operator=(__non_propagating_cache&& __other) noexcept { - this->reset(); - __other.reset(); + this->_M_reset(); + __other._M_reset(); return *this; } - using optional<_Tp>::operator*; + constexpr _Tp& + operator*() noexcept + { return this->_M_get(); } template<typename _Iter> _Tp& _M_emplace_deref(const _Iter& __i) { - this->reset(); - return this->emplace(*__i); + this->_M_reset(); + ::new ((void *) std::__addressof(this->_M_payload._M_payload)) _Tp(*__i); + this->_M_payload._M_engaged = true; + return this->_M_get(); } }; }