C++ Logo


Advanced search

std::array lvalue access methods

From: Kevin Bracey <kevin_at_[hidden]>
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?

Received on 2019-07-06 06:22:27