Issue 2485: get() should be overloaded for const tuple&& (original) (raw)
This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of C++17 status.
Section: 22.4.8 [tuple.elem] Status: C++17 Submitter: Stephan T. Lavavej Opened: 2015-03-27 Last modified: 2017-07-30
const rvalues are weird, but they're part of the type system. Consider the following code:
#include #include #include
using namespace std;
string str1() { return "one"; } const string str2() { return "two"; } tuple tup3() { return make_tuple("three"); } const tuple tup4() { return make_tuple("four"); }
int main() { // cref(str1()); // BAD, properly rejected // cref(str2()); // BAD, properly rejected // cref(get<0>(tup3())); // BAD, properly rejected cref(get<0>(tup4())); // BAD, but improperly accepted! }
As tuple is a fundamental building block (and the only convenient way to have variadic data members), it should not open a hole in the type system. get() should imitate 7.6.1.5 [expr.ref]'s rules for accessing data members. (This is especially true for pair, where both get<0>() and .first are available.)
While we're in the neighborhood, we can dramatically simplify the wording here. All we need to do is follow 22.4.8 [tuple.elem]/9's example of saying "Returns: A reference to STUFF", and allow implementers to figure out how to achieve that with the given return types.
TP: for the existing overloads there's no change to the code, just descriptions?
STL: right.
JW: I love it
MC: in favor of moving to Ready and bringing up for vote on Friday
7 in favor, none opposed
This wording is relative to N4296.
- Change 22.2 [utility]/2 "Header
<utility>synopsis" as depicted:[…]
template<size_t I, class T1, class T2>
constexpr tuple_element_t<I, pair<T1, T2>>&
get(pair<T1, T2>&) noexcept;
template<size_t I, class T1, class T2>
constexpr tuple_element_t<I, pair<T1, T2>>&&
get(pair<T1, T2>&&) noexcept;
template<size_t I, class T1, class T2>
constexpr const tuple_element_t<I, pair<T1, T2>>&
get(const pair<T1, T2>&) noexcept;
template<size_t I, class T1, class T2>
constexpr const tuple_element_t<I, pair<T1, T2>>&&
get(const pair<T1, T2>&&) noexcept;
template <class T, class U>
constexpr T& get(pair<T, U>& p) noexcept;
template <class T, class U>
constexpr const T& get(const pair<T, U>& p) noexcept;
template <class T, class U>
constexpr T&& get(pair<T, U>&& p) noexcept;
template <class T, class U>
constexpr const T&& get(const pair<T, U>&& p) noexcept;
template <class T, class U>
constexpr T& get(pair<U, T>& p) noexcept;
template <class T, class U>
constexpr const T& get(const pair<U, T>& p) noexcept;
template <class T, class U>
constexpr T&& get(pair<U, T>&& p) noexcept;
template <class T, class U>
constexpr const T&& get(const pair<U, T>&& p) noexcept;
[…] - Change 22.4.1 [tuple.general]/2 "Header
<tuple>synopsis" as depicted:[…]
// 20.4.2.6, element access:
template <size_t I, class... Types>
constexpr tuple_element_t<I, tuple<Types...>>&
get(tuple<Types...>&) noexcept;
template <size_t I, class... Types>
constexpr tuple_element_t<I, tuple<Types...>>&&
get(tuple<Types...>&&) noexcept;
template <size_t I, class... Types>
constexpr const tuple_element_t<I, tuple<Types...>>&
get(const tuple<Types...>&) noexcept;
template <size_t I, class... Types>
constexpr const tuple_element_t<I, tuple<Types...>>&&
get(const tuple<Types...>&&) noexcept;
template <class T, class... Types>
constexpr T& get(tuple<Types...>& t) noexcept;
template <class T, class... Types>
constexpr T&& get(tuple<Types...>&& t) noexcept;
template <class T, class... Types>
constexpr const T& get(const tuple<Types...>& t) noexcept;
template <class T, class... Types>
constexpr const T&& get(const tuple<Types...>&& t) noexcept;
[…] - Change 23.3.1 [sequences.general]/2 "Header
<array>synopsis" as depicted:[…]
template <size_t I, class T, size_t N>
constexpr T& get(array<T, N>&) noexcept;
template <size_t I, class T, size_t N>
constexpr T&& get(array<T, N>&&) noexcept;
template <size_t I, class T, size_t N>
constexpr const T& get(const array<T, N>&) noexcept;
template <size_t I, class T, size_t N>
constexpr const T&& get(const array<T, N>&&) noexcept;
[…] - Change 22.3.4 [pair.astuple] as depicted:
template<size_t I, class T1, class T2>
constexpr tuple_element_t<I, pair<T1, T2>>&
get(pair<T1, T2>& p) noexcept;
template<size_t I, class T1, class T2>
constexpr const tuple_element_t<I, pair<T1, T2>>&
get(const pair<T1, T2>& p) noexcept;-3- Returns: IfI == 0returnsp.first; ifI == 1returnsp.second; otherwise the program is ill-formed.template<size_t I, class T1, class T2>
constexpr tuple_element_t<I, pair<T1, T2>>&&
get(pair<T1, T2>&& p) noexcept;
template<size_t I, class T1, class T2>
constexpr const tuple_element_t<I, pair<T1, T2>>&&
get(const pair<T1, T2>&& p) noexcept;-4- Returns: If
I == 0returns a reference to~~std::forward<T1&&>(~~p.first~~)~~; ifI == 1returns a reference to~~std::forward<T2&&>(~~p.second~~)~~; otherwise the program is ill-formed.template <class T, class U>
constexpr T& get(pair<T, U>& p) noexcept;
template <class T, class U>
constexpr const T& get(const pair<T, U>& p) noexcept;-5- Requires:TandUare distinct types. Otherwise, the program is ill-formed.-6- Returns:get<0>(p);template <class T, class U>
constexpr T&& get(pair<T, U>&& p) noexcept;
template <class T, class U>
constexpr const T&& get(const pair<T, U>&& p) noexcept;-7- Requires:
TandUare distinct types. Otherwise, the program is ill-formed.-8- Returns: A reference to
p.first.get<0>(std::move(p));template <class T, class U>
constexpr T& get(pair<U, T>& p) noexcept;
template <class T, class U>
constexpr const T& get(const pair<U, T>& p) noexcept;-9- Requires:TandUare distinct types. Otherwise, the program is ill-formed.-10- Returns:get<1>(p);template <class T, class U>
constexpr T&& get(pair<U, T>&& p) noexcept;
template <class T, class U>
constexpr const T&& get(const pair<U, T>&& p) noexcept;-11- Requires:
TandUare distinct types. Otherwise, the program is ill-formed.-12- Returns: A reference to
p.second.get<1>(std::move(p)); - Change 22.4.8 [tuple.elem] as depicted:
template <size_t I, class... Types>
constexpr tuple_element_t<I, tuple<Types...> >& get(tuple<Types...>& t) noexcept;-1- Requires:I < sizeof...(Types). The program is ill-formed ifIis out of bounds.-2- Returns: A reference to theIth element oft, where indexing is zero-based.template <size_t I, class... Types>
constexpr tuple_element_t<I, tuple<Types...> >&& get(tuple<Types...>&& t) noexcept; // Note A-3- Effects: Equivalent to return std::forward<typename tuple_element<I, tuple<Types...> >::type&&>(get(t));-4- Note: if aTinTypesis some reference typeX&, the return type isX&, notX&&. However, if the element type is a non-reference typeT, the return type isT&&.template <size_t I, class... Types>
constexpr tuple_element_t<I, tuple<Types...> > const& get(const tuple<Types...>& t) noexcept; // Note B
template <size_t I, class... Types>
constexpr const tuple_element_t<I, tuple<Types...> >&& get(const tuple<Types...>&& t) noexcept;-5- Requires:
I < sizeof...(Types). The program is ill-formed ifIis out of bounds.-6- Returns: A
constreference to theIth element oft, where indexing is zero-based.-?- [Note A: if a
TinTypesis some reference typeX&, the return type isX&, notX&&. However, if the element type is a non-reference typeT, the return type isT&&. — _end note_]-7- [Note B: Constness is shallow. If a
TinTypesis some reference typeX&, the return type isX&, notconst X&. However, if the element type is non-reference typeT, the return type isconst T&. This is consistent with how constness is defined to work for member variables of reference type. — _end note_]template <class T, class... Types>
constexpr T& get(tuple<Types...>& t) noexcept;
template <class T, class... Types>
constexpr T&& get(tuple<Types...>&& t) noexcept;
template <class T, class... Types>
constexpr const T& get(const tuple<Types...>& t) noexcept;
template <class T, class... Types>
constexpr const T&& get(const tuple<Types...>&& t) noexcept;-8- Requires: The type
Toccurs exactly once inTypes.... Otherwise, the program is ill-formed.-9- Returns: A reference to the element of
tcorresponding to the typeTinTypes....[…]
- Change 23.3.3.7 [array.tuple] as depicted:
template <size_t I, class T, size_t N>
constexpr T& get(array<T, N>& a) noexcept;-3- Requires:I < N. The program is ill-formed ifIis out of bounds.-4- Returns: A reference to theIth element ofa, where indexing is zero-based.template <size_t I, class T, size_t N>
constexpr T&& get(array<T, N>&& a) noexcept;-5- Effects: Equivalent toreturn std::move(get<I>(a));template <size_t I, class T, size_t N>
constexpr const T& get(const array<T, N>& a) noexcept;
template <size_t I, class T, size_t N>
constexpr const T&& get(const array<T, N>&& a) noexcept;-6- Requires:
I < N. The program is ill-formed ifIis out of bounds.-7- Returns: A
constreference to theIth element ofa, where indexing is zero-based.