https://gcc.gnu.org/bugzilla/show_bug.cgi?id=119469
--- Comment #4 from Jonathan Wakely <redi at gcc dot gnu.org> --- The return type of std::move is an rvalue reference type, but the std::move(fun) expression produces an lvalue (because the standard says so). So although the return type of std::move(fun) is int(&&)(int), what you get is an lvalue and so decltype(std::move(fun)) is int(&)(int). Even though that's not the return type. 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>())); Because this uses decltype(static_cast<__rval>(*E)) it gives us the right answer, where previously we just used __rval which was wrong for the function reference case.