Date: Sat, 6 Jul 2019 14:20:29 +0300
Looking at std::array and std::get, I came across LWG 2485, which
added "get(const tuple &&)" overloads to plug a hole where
get could silently produce a const lvalue reference to an rvalue.
It seems that fully covered access to pairs and tuples, but doesn't
array have a type hole in its own methods? Like this:
array<int, 2> arr() { return array<int, 2>{1, 2}; }
const array<int, 2> carr() { return array<int, 2>{1, 2}; }
cref(get<0>(arr())); // BAD - rejected before LWG 2485
cref(get<0>(carr())); // BAD - rejected after LWG 2485
cref(carr()); // BAD - rejected
cref(arr()); // BAD - rejected
cref(carr()[0]); // BAD - accepted!
cref(arr()[0]); // BAD - accepted!
const array<int, 2> &r1 = arr(); // OK - lifetime extension
const int &r2 = arr()[0]; // BAD - accepted!, dangling reference
I believe array's operator[], at(), front(), back() should have &/&&
overloads, as per get():
constexpr value_type &operator[](size_type) &;
constexpr value_type &&operator[](size_type) &&;
constexpr const value_type &operator[](size_type) const &;
constexpr const value_type &&operator[](size_type) const &&;
Without this change, std::array has a type hole that native arrays don't.
However, tightening that would deviate more from SequenceContainer,
which requires lvalue reference returns.
Comparing other in-place containers, std::tuple and std::variant are
fine, as they're only accessed via get(), and pair's first and last
members are handled by the language; std::optional does have access
operators like this.
But is any_cast possibly missing a (const &&) overload?
added "get(const tuple &&)" overloads to plug a hole where
get could silently produce a const lvalue reference to an rvalue.
It seems that fully covered access to pairs and tuples, but doesn't
array have a type hole in its own methods? Like this:
array<int, 2> arr() { return array<int, 2>{1, 2}; }
const array<int, 2> carr() { return array<int, 2>{1, 2}; }
cref(get<0>(arr())); // BAD - rejected before LWG 2485
cref(get<0>(carr())); // BAD - rejected after LWG 2485
cref(carr()); // BAD - rejected
cref(arr()); // BAD - rejected
cref(carr()[0]); // BAD - accepted!
cref(arr()[0]); // BAD - accepted!
const array<int, 2> &r1 = arr(); // OK - lifetime extension
const int &r2 = arr()[0]; // BAD - accepted!, dangling reference
I believe array's operator[], at(), front(), back() should have &/&&
overloads, as per get():
constexpr value_type &operator[](size_type) &;
constexpr value_type &&operator[](size_type) &&;
constexpr const value_type &operator[](size_type) const &;
constexpr const value_type &&operator[](size_type) const &&;
Without this change, std::array has a type hole that native arrays don't.
However, tightening that would deviate more from SequenceContainer,
which requires lvalue reference returns.
Comparing other in-place containers, std::tuple and std::variant are
fine, as they're only accessed via get(), and pair's first and last
members are handled by the language; std::optional does have access
operators like this.
But is any_cast possibly missing a (const &&) overload?
Received on 2019-07-06 06:22:27