ericniebler/stl2

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.

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.