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.
get()
should be overloaded for const tuple&&
Section: 22.4.8 [tuple.elem] Status: C++17 Submitter: Stephan T. Lavavej Opened: 2015-03-27 Last modified: 2017-07-30
Priority: 1
View all other issues in [tuple.elem].
View all issues with C++17 status.
Discussion:
const
rvalues are weird, but they're part of the type system. Consider the following code:
#include <functional> #include <string> #include <tuple> using namespace std; string str1() { return "one"; } const string str2() { return "two"; } tuple<string> tup3() { return make_tuple("three"); } const tuple<string> 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.)
[2015-05, Lenexa]
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
Proposed resolution:
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 == 0
returnsp.first
; ifI == 1
returnsp.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 == 0
returns a reference to; if
std::forward<T1&&>(p.first)I == 1
returns a reference to; otherwise the program is ill-formed.
std::forward<T2&&>(p.second)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:T
andU
are 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:
-8- Returns: A reference toT
andU
are distinct types. Otherwise, the program is ill-formed.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:T
andU
are 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:
-12- Returns: A reference toT
andU
are distinct types. Otherwise, the program is ill-formed.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 ifI
is out of bounds.-2- Returns: A reference to theI
th 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<I>(t));-4- Note: if aT
inTypes
is 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:
-6- Returns: AI < sizeof...(Types)
. The program is ill-formed ifI
is out of bounds.constreference to theI
th element oft
, where indexing is zero-based. -?- [Note A: if aT
inTypes
is 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 aT
inTypes
is 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
-9- Returns: A reference to the element ofT
occurs exactly once inTypes...
. Otherwise, the program is ill-formed.t
corresponding to the typeT
inTypes...
. […]
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 ifI
is out of bounds.-4- Returns: A reference to theI
th 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:
-7- Returns: AI < N
. The program is ill-formed ifI
is out of bounds.constreference to theI
th element ofa
, where indexing is zero-based.