tuple_size_v/tuple_element_t
should be available when tuple_size/tuple_element
areSection: 22.4.2 [tuple.syn], 22.4.7 [tuple.helper] Status: New Submitter: Casey Carter Opened: 2020-01-17 Last modified: 2021-11-04
Priority: 3
View all issues with New status.
Discussion:
22.4.7 [tuple.helper]/6 makes the const
/volatile
/const volatile
partial
specializations of tuple_size
available when any of <array>
, <ranges>
,
<span>
, or <utility>
is included. 22.4.7 [tuple.helper]/8 makes the
const
/volatile
/const volatile
partial specializations of tuple_element
available when any of those same headers is included. This leads to a couple of problems:
For users of the Standard Library, it's not helpful to have these partial specializations of class
templates available when the preferred interface — the variable template tuple_size_v
and
alias template tuple_element_t
— are not.
For specifiers of the Standard Library, we must update two distinct yet identical lists of headers that make this same set of templates available when adding another header.
We could solve both of these problems by coalescing the two paragraphs into one and including the variable and alias template in the set of declarations made available by the pertinent (now single) list of headers.
[2020-02-08 Issue Prioritization]
Priority to 3 after reflector discussion. Tim Song said: It’s not clear that entities only mentioned in the synopsis are "defined in this subclause".
[2021-11-04; Jonathan Wakely adds note]
The __cpp_lib_tuple_element_t
macro in
17.3.2 [version.syn] should be updated too.
Proposed resolution:
This wording is relative to N4842.
Modify 22.4.2 [tuple.syn], header <tuple>
synopsis, as indicated:
namespace std { […] // 22.4.7 [tuple.helper], tuple helper classes template<class T> struct tuple_size; // not defined template<class T> struct tuple_size<const T>; template<class T> struct tuple_size<volatile T>; template<class T> struct tuple_size<const volatile T>; template<class T> inline constexpr size_t tuple_size_v = tuple_size<T>::value;template<class... Types> struct tuple_size<tuple<Types...>>;template<size_t I, class T> struct tuple_element; // not defined template<size_t I, class T> struct tuple_element<I, const T>; template<size_t I, class T> struct tuple_element<I, volatile T>; template<size_t I, class T> struct tuple_element<I, const volatile T>;template<size_t I, class... Types> struct tuple_element<I, tuple<Types...>>;template<size_t I, class T> using tuple_element_t = typename tuple_element<I, T>::type; // 22.4.8 [tuple.elem], element access template<class... Types> struct tuple_size<tuple<Types...>>; template<size_t I, class... Types> struct tuple_element<I, tuple<Types...>>; 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; […]// 22.4.7 [tuple.helper], tuple helper classestemplate<class T> inline constexpr size_t tuple_size_v = tuple_size<T>::value;}
Modify 22.4.7 [tuple.helper] as indicated:
20.5.6 Tuple helper classes [tuple.helper]
-?- In addition to being available via inclusion of the<tuple>
header, the entities defined in this subclause [tuple.helper] are available when any of the headers<array>
(23.3.2 [array.syn]),<ranges>
(25.2 [ranges.syn]),<span>
(23.7.2.1 [span.syn]), or<utility>
(22.2.1 [utility.syn]) are included.template<class T> struct tuple_size;-1- Remarks: All specializations of
tuple_size
shall meet the Cpp17UnaryTypeTrait requirements (21.3.2 [meta.rqmts]) with a base characteristic ofintegral_constant<size_t, N>
for someN
.template<class... Types> struct tuple_size<tuple<Types...>> : public integral_constant<size_t, sizeof...(Types)> { }; template<size_t I, class... Types> struct tuple_element<I, tuple<Types...>> { using type = TI; };
-2- Requires:I < sizeof...(Types)
. The program is ill-formed ifI
is out of bounds.-3- Type:TI
is the type of theIth
element ofTypes
, where indexing is zero-based.template<class T> struct tuple_size<const T>; template<class T> struct tuple_size<volatile T>; template<class T> struct tuple_size<const volatile T>;-4- Let
TS
denotetuple_size<T>
of the cv-unqualified typeT
. If the expressionTS::value
is well-formed when treated as an unevaluated operand, then each of the three templates shall meet the Cpp17UnaryTypeTrait requirements (21.3.2 [meta.rqmts]) with a base characteristic ofOtherwise, they shall have no member value. -5- Access checking is performed as if in a context unrelated tointegral_constant<size_t, TS::value>TS
andT
. Only the validity of the immediate context of the expression is considered. [Note: The compilation of the expression can result in side effects such as the instantiation of class template specializations and function template specializations, the generation of implicitly-defined functions, and so on. Such side effects are not in the "immediate context" and can result in the program being ill-formed. — end note]-6- In addition to being available via inclusion of the<tuple>
header, the three templates are available when any of the headers<array>
(23.3.2 [array.syn]),<ranges>
(25.2 [ranges.syn]),<span>
(23.7.2.1 [span.syn]), or<utility>
(22.2.1 [utility.syn]) are included.template<size_t I, class T> struct tuple_element<I, const T>; template<size_t I, class T> struct tuple_element<I, volatile T>; template<size_t I, class T> struct tuple_element<I, const volatile T>;-7- Let
TE
denotetuple_element_t<I, T>
of the cv-unqualified typeT
. Then each of the three templates shall meet the Cpp17TransformationTrait requirements (21.3.2 [meta.rqmts]) with a member typedef type that names the following type:
(7.1) — for the first specialization,
add_const_t<TE>
,(7.2) — for the second specialization,
add_volatile_t<TE>
, and(7.3) — for the third specialization,
add_cv_t<TE>
.-8- In addition to being available via inclusion of the<tuple>
header, the three templates are available when any of the headers<array>
(23.3.2 [array.syn]),<ranges>
(25.2 [ranges.syn]),<span>
(23.7.2.1 [span.syn]), or<utility>
(22.2.1 [utility.syn]) are included.
Modify 22.4.8 [tuple.elem] as indicated:
[Drafting note: Since this issue performs colliding text changes with P1460R0, we perform similar wording changes as suggested on page 19 [tuple.helper] p2.]
20.5.7 Element access [tuple.elem]
template<class... Types> struct tuple_size<tuple<Types...>> : public integral_constant<size_t, sizeof...(Types)> { }; template<size_t I, class... Types> struct tuple_element<I, tuple<Types...>> { using type = TI; };-?- Mandates:
-?- Type:I < sizeof...(Types)
.TI
is the type of theIth
element ofTypes
, where indexing is zero-based.template<size_t I, class... Types> constexpr tuple_element_t<I, tuple<Types...>>& get(tuple<Types...>& t) noexcept; […][…]