https://gcc.gnu.org/bugzilla/show_bug.cgi?id=119469
--- Comment #6 from Jonathan Wakely <redi at gcc dot gnu.org> --- (In reply to Jonathan Wakely from comment #4) > So we can still avoid the cost of doing overload resolution for > std::move(*E) like so: > > using __lval = __iter_ref_t<_Tp>; > using __rval = remove_reference_t<__lval>&&; > // N.B. this is not just __rval, because casting to an rvalue > // reference to function type produces an lvalue not an rvalue. > // C++23 [expr.static.cast]/1, [expr.type.conv]/1 etc. > using type = decltype(static_cast<__rval>(std::declval<__lval>())); Actually we don't even need the cast, just decltype(declval<__rval>()) gives the right answer. And declval always adds && so decltype(declval<remove_reference_t<__lval>>()) is the same type, and so: using type = decltype(std::declval<remove_reference_t<__iter_ref_t<_Tp>>>());