https://gcc.gnu.org/bugzilla/show_bug.cgi?id=95910
--- Comment #3 from Patrick Palka <ppalka at gcc dot gnu.org> --- (In reply to Rene Rahn from comment #2) > Ok, thanks for the explanation. I do understand the issue now and why it > causes the hard error and not an substitution failure. > But honestly, given that it works for container because they are wrapped in > a ref_view with pointer semantics, makes this very hard to understand. Hmm yes, it seems (for the record) the reason this works for std::vector is because views::transform wraps the type in a ref_view, and ref_view's const-qualified begin() member returns a non-const iterator. So both range_reference_t<_Vp> and range_reference_t<const _Vp> (where _Vp = ref_view<vector<int>>) resolve to int&. On the other hand, single_view<T>'s const-qualified begin() member returns a pointer to const T, so range_reference_t<const _Vp> (with _Vp = single_view) resolves to const int&. And so when we go to check the constraints of transform_view::begin() const we end up instantiating the lambda with a const int& argument, leading to a hard error. > And basically, if you transform something that calls somewhere in the stack a > function with auto return type you might not be able to even do > `decltype(expression)` to get the return type deduced any more, because the > compiler has to instantiate the expression. > > That makes generic code with auto return types kind of difficult to use, > does it? I mean, especially as a library writer I must make sure that the > client can use my methods/types in these contexts. And it feels plausible > that types are constrained to be mutable somewhere in this context. > Is there a general trick to avoid this, except guaranteeing to know the > return type before the expression is evaluated? Hmm, if you can't easily specify a concrete return type, then you could maybe try constraining the lambda appropriately. In this particular example you could replace the static_assert with an analogous require-clause, which would turn the hard error into a SFINAE-friendly error. We've also been bitten by using a deduced auto return type instead of a concrete return type, in particular in the definitions of the ranges::empty() and ranges::iter_move() CPOs, see e.g. PR93978 and PR92894. > > Many thanks for your help!