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!

Reply via email to