https://gcc.gnu.org/bugzilla/show_bug.cgi?id=92894
--- Comment #8 from Jonathan Wakely <redi at gcc dot gnu.org> --- Fixed on master (GCC 11) so far. Clang's error is a bit more explicit about the problem: error: function 'std::projected<X *, std::identity>::operator*' is used but not defined in this translation unit, and cannot be defined in any other translation unit because its type does not have linkage For a type with external linkage the ranges::iter_move::operator() function still gets instantiated, but the compiler doesn't reject it immediately because it's possible that projected<X*, identity>::operator* is defined in another translation unit. Since the function isn't actually called (just instantiated to find its return type) there's no reference to it in the final object, and so it doesn't matter that projected::operator* isn't defined anywhere. The program is still ill-formed, but no diagnostic is required and it "works". For a type with internal linkage (like a local class) the compiler stops immediately, diagnosing the ill-formed call to projected::operator*. So without this fix it's not possible to use most std::ranges:: algos with local classes.