This is what I came up with:
template<std::ranges::range R>
auto foo_coroutine(R&& rng) {
if constexpr (std::is_lvalue_reference_v<R>)
return foo_coroutine_impl(std::ranges::subrange{rng}, std::move(func));
else if constexpr (std::ranges::borrowed_range<R>)
return foo_coroutine_impl(std::move(rng), std::move(func));
//Deduction fails for rvalue non borrowed ranges
}
auto foo_coroutine_impl(const std::ranges::borrowed_range auto rng) {
/*...*/
}