Redesign begin/end CPOs to eliminate deprecated behavior
ericniebler opened this issue · 5 comments
... and to force range types to opt in to working with rvalues, thereby giving users a way to detect that, for a particular range type, iterator validity does not depend on the range's lifetime.
E.g. (untested):
namespace _begin_ {
template <class T>
void begin(T &&) = delete;
struct fn {
// Member begin/end need lvalues:
template <class T>
Iterator operator()(T& t) const -> decltype(t.begin()) {
return t.begin();
}
// ADL begin/end permit rvalues:
template <class T>
Iterator operator()(T&& t) const -> decltype(begin((T&& ) t)) {
return begin((T&& ) t);
}
// array begin/end require lvalues:
template <class T, std::size_t N>
T *operator()(T (&t)[N]) {
return t;
}
};
inline constexpr fn begin {};
}
using _begin_::begin;
Proposed Resolution
Apply P0970R1.
attn @CaseyCarter
To avoid ramifications that would require redesign of iterator_t
and sentinel_t
, we need to ensure/require that the return type of begin
and end
is insensitive to value category for ranges which provide rvalue begin
and end
. In other words, Same<decltype(begin(r)), decltype(begin(move(r))>
(and Same<decltype(begin(as_const(r))), decltype(begin(move(as_const(r)))>
, if the expressions are valid) should hold.
That seems sensible. It also strikes me as a syntactic constraint that could be described in words and not enforced by the concepts, much like the implicit expression variations.
P0896R2 incorporates P0970R1, and therefore the PR for this issue.
Resolved by incorporation of P0896R4 into the C++ Working Draft in San Diego.