std::tuple_element

From cppreference.com
< cpp‎ | utility
 
 
Utilities library
General utilities
Relational operators (deprecated in C++20)
 
Defined in header <tuple>
Defined in header <array>
Defined in header <utility>
Defined in header <ranges>
(since C++20)
Defined in header <complex>
(since C++26)
template< std::size_t I, class T >
struct tuple_element; // not defined
(1) (since C++11)
template< std::size_t I, class T >

struct tuple_element< I, const T > {
    using type = typename
        std::add_const<typename std::tuple_element<I, T>::type>::type;

};
(2) (since C++11)
template< std::size_t I, class T >

struct tuple_element< I, volatile T > {
    using type = typename
        std::add_volatile<typename std::tuple_element<I, T>::type>::type;

};
(3) (since C++11)
(deprecated in C++20)
template< std::size_t I, class T >

struct tuple_element< I, const volatile T > {
    using type = typename
        std::add_cv<typename std::tuple_element<I, T>::type>::type;

};
(4) (since C++11)
(deprecated in C++20)

Provides compile-time indexed access to the types of the elements of a tuple-like type.

1) The primary template is not defined. An explicit (full) or partial specialization is required to make a type tuple-like.
2-4) Specializations for cv-qualified types simply add corresponding cv-qualifiers by default.

std::tuple_element interacts with the core language: it can provide structured binding support in the tuple-like case.

(since C++17)

Specializations

The standard library provides following specializations for standard library types:

obtains the type of the specified element
(class template specialization)
obtains the type of the elements of pair
(class template specialization)
obtains the type of the elements of array
(class template specialization)
obtains the type of the iterator or the sentinel of a std::ranges::subrange
(class template specialization)
obtains the underlying real and imaginary number type of a std::complex
(class template specialization)

Users may specialize std::tuple_element for program-defined types to make them tuple-like.

In normal cases where the get functions returns reference members or reference to subobjects, only specializations for cv-unqualified types are needed to be customized.

Member types

Member type Definition
type for a standard specialization, the type of Ith element of the tuple-like type T, where I is in [0std::tuple_size<T>::value)

Helper types

Defined in header <tuple>
template< std::size_t I, class T >
using tuple_element_t = typename tuple_element<I, T>::type;
(since C++14)

Notes

Feature-test macro Value Std Feature
__cpp_lib_tuple_element_t 201402L (C++14) std::tuple_element_t

Example

#include <array>
#include <cstddef>
#include <iostream>
#include <ranges>
#include <tuple>
#include <type_traits>
#include <utility>
 
template<typename T1, typename T2, typename T3>
struct Triple
{
    T1 t1;
    T2 t2;
    T3 t3;
};
 
// A specialization of std::tuple_element for program-defined type Triple:
template<std::size_t I, typename T1, typename T2, typename T3>
    struct std::tuple_element<I, Triple<T1, T2, T3>>
    { static_assert(false, "Invalid index"); }; 
template<typename T1, typename T2, typename T3>
    struct std::tuple_element<0, Triple<T1, T2, T3>> { using type = T1; };
template<typename T1, typename T2, typename T3>
    struct std::tuple_element<1, Triple<T1, T2, T3>> { using type = T2; };
template<typename T1, typename T2, typename T3>
    struct std::tuple_element<2, Triple<T1, T2, T3>> { using type = T3; };
 
 
template<typename... Args> struct TripleTypes
{
    static_assert(3 == sizeof...(Args), "Expected exactly 3 type names");
    template<std::size_t N>
    using type = typename std::tuple_element_t<N, Triple<Args...>>;
};
 
int main()
{
    TripleTypes<char, int, float>::type<1> i{42};
    std::cout << i << '\n';
 
    using Tri = Triple<int, char, short>; //< Program-defined type
    static_assert(std::is_same_v<std::tuple_element_t<0, Tri>, int> &&
                  std::is_same_v<std::tuple_element_t<1, Tri>, char> &&
                  std::is_same_v<std::tuple_element_t<2, Tri>, short>);
 
    using Tuple = std::tuple<int, char, short>;
    static_assert(std::is_same_v<std::tuple_element_t<0, Tuple>, int> &&
                  std::is_same_v<std::tuple_element_t<1, Tuple>, char> &&
                  std::is_same_v<std::tuple_element_t<2, Tuple>, short>);
 
    using Array3 = std::array<int, 3>;
    static_assert(std::is_same_v<std::tuple_element_t<0, Array3>, int> &&
                  std::is_same_v<std::tuple_element_t<1, Array3>, int> &&
                  std::is_same_v<std::tuple_element_t<2, Array3>, int>);
 
    using Pair = std::pair<Tuple, Tri>;
    static_assert(std::is_same_v<std::tuple_element_t<0, Pair>, Tuple> &&
                  std::is_same_v<std::tuple_element_t<1, Pair>, Tri>);
 
    using Sub = std::ranges::subrange<int*, int*>;
    static_assert(std::is_same_v<std::tuple_element_t<0, Sub>, int*> &&
                  std::is_same_v<std::tuple_element_t<1, Sub>, int*>);
}

Output:

42

Defect reports

The following behavior-changing defect reports were applied retroactively to previously published C++ standards.

DR Applied to Behavior as published Correct behavior
LWG 2212 C++11 specializations for cv types were not required in some headers, which led to ambiguity required

See also

Structured binding (C++17) binds the specified names to sub-objects or tuple elements of the initializer
obtains the number of elements of a tuple-like type
(class template)
(C++11)
creates a tuple by concatenating any number of tuples
(function template)