Namespaces
Variants

std::tuple<Types...>::tuple

De es.cppreference.net
 
 
Biblioteca de utilidades
Soporte del lenguaje
Soporte de tipos (tipos básicos, RTTI)
Macros de prueba de características de la biblioteca (C++20)
Utilidades del programa
Funciones variádicas
Soporte de corrutinas (C++20)
Soporte de contratos (C++26)
Comparación tripartita
(C++20)
(C++20)(C++20)(C++20)    
(C++20)(C++20)(C++20)

Utilidades generales
Operadores relacionales (obsoleto en C++20)
 
 
Definido en el encabezado <tuple>
constexpr tuple();
(1) (desde C++11)
(explícito condicionalmente)
tuple( const Types&... args );
(2) (desde C++11)
(constexpr desde C++14)
(explícito condicionalmente)
template< class... UTypes >
tuple( UTypes&&... args );
(3) (desde C++11)
(constexpr desde C++14)
(explícito condicionalmente)
template< class... UTypes >
constexpr tuple( tuple<UTypes...>& other );
(4) (desde C++23)
(explícito condicionalmente)
template< class... UTypes >
tuple( const tuple<UTypes...>& other );
(5) (desde C++11)
(constexpr desde C++14)
(explícito condicionalmente)
template< class... UTypes >
tuple( tuple<UTypes...>&& other );
(6) (desde C++11)
(constexpr desde C++14)
(explícito condicionalmente)
template< class... UTypes >
constexpr tuple( const tuple<UTypes...>&& other );
(7) (desde C++23)
(explícito condicionalmente)
template< class U1, class U2 >
constexpr tuple( std::pair<U1, U2>& p );
(8) (desde C++23)
(explícito condicionalmente)
template< class U1, class U2 >
tuple( const std::pair<U1, U2>& p );
(9) (desde C++11)
(constexpr desde C++14)
(explícito condicionalmente)
template< class U1, class U2 >
tuple( std::pair<U1, U2>&& p );
(10) (desde C++11)
(constexpr desde C++14)
(explícito condicionalmente)
template< class U1, class U2 >
constexpr tuple( const std::pair<U1, U2>&& p );
(11) (desde C++23)
(explícito condicionalmente)
template< tuple-like UTuple >
constexpr tuple( UTuple&& u );
(12) (desde C++23)
(explícito condicionalmente)
tuple( const tuple& other ) = default;
(13) (desde C++11)
tuple( tuple&& other ) = default;
(14) (desde C++11)
Constructores con extensión de asignador
template< class Alloc >
tuple( std::allocator_arg_t, const Alloc& a );
(15) (desde C++11)
(constexpr desde C++20)
(explícito condicionalmente)
template< class Alloc >
tuple( std::allocator_arg_t, const Alloc& a,
       const Types&... args );
(16) (desde C++11)
(constexpr desde C++20)
(explícito condicionalmente)
template< class Alloc, class... UTypes >
tuple( std::allocator_arg_t, const Alloc& a,
       UTypes&&... args );
(17) (desde C++11)
(constexpr desde C++20)
(explícito condicionalmente)
template< class Alloc, class... UTypes >
constexpr tuple( std::allocator_arg_t, const Alloc& a,
                 tuple<UTypes...>& other );
(18) (desde C++23)
(explícito condicionalmente)
template< class Alloc, class... UTypes >
tuple( std::allocator_arg_t, const Alloc& a,
       const tuple<UTypes...>& other );
(19) (desde C++11)
(constexpr desde C++20)
(explícito condicionalmente)
template< class Alloc, class... UTypes >
tuple( std::allocator_arg_t, const Alloc& a,
       tuple<UTypes...>&& other );
(20) (desde C++11)
(constexpr desde C++20)
(explícito condicionalmente)
template< class Alloc, class... UTypes >
constexpr tuple( std::allocator_arg_t, const Alloc& a,
                 const tuple<UTypes...>&& other );
(21) (desde C++23)
(explícito condicionalmente)
template< class Alloc, class U1, class U2 >
constexpr tuple( std::allocator_arg_t, const Alloc& a,
                 std::pair<U1, U2>& p );
(22) (desde C++23)
(explícito condicionalmente)
template< class Alloc, class U1, class U2 >
tuple( std::allocator_arg_t, const Alloc& a,
       const std::pair<U1, U2>& p );
(23) (desde C++11)
(constexpr desde C++20)
(explícito condicionalmente)
template< class Alloc, class U1, class U2 >
tuple( std::allocator_arg_t, const Alloc& a,
       std::pair<U1, U2>&& p );
(24) (desde C++11)
(constexpr desde C++20)
(explícito condicionalmente)
template< class Alloc, class U1, class U2 >
constexpr tuple( std::allocator_arg_t, const Alloc& a,
                 const std::pair<U1, U2>&& p );
(25) (desde C++23)
(explícito condicionalmente)
template< class Alloc, tuple-like UTuple >
constexpr tuple( std::allocator_arg_t, const Alloc& a, UTuple&& u );
(26) (desde C++23)
(explícito condicionalmente)
template< class Alloc >
tuple( std::allocator_arg_t, const Alloc& a,
       const tuple& other );
(27) (desde C++11)
(constexpr desde C++20)
template< class Alloc >
tuple( std::allocator_arg_t, const Alloc& a,
       tuple&& other );
(28) (desde C++11)
(constexpr desde C++20)

Construye una nueva tupla.

En las descripciones que siguen, sea

  • i en el rango [0, sizeof...(Types)) en orden,
  • Ti el iésimo tipo en Types, y
  • Ui el iésimo tipo en un paquete de parámetros de plantilla llamado UTypes,

donde la indexación comienza en cero.

1) Constructor por defecto. Inicializa por valor todos los elementos, si los hay. El constructor por defecto es trivial si sizeof...(Types) == 0.
  • Esta sobrecarga participa en la resolución de sobrecarga solo si std::is_default_constructible<Ti>::value es true para todo i.
  • El constructor es explicit si y solo si Ti no es inicializable por lista de copia desde {} para al menos un i.
2) Constructor directo. Inicializa cada elemento de la tupla con el parámetro correspondiente.
  • Esta sobrecarga participa en la resolución de sobrecarga solo si sizeof...(Types) >= 1 y std::is_copy_constructible<Ti>::value es true para todo i.
  • Este constructor es explicit si y solo si std::is_convertible<const Ti&, Ti>::value es false para al menos un i.
3) Constructor de conversión. Inicializa cada elemento de la tupla con el valor correspondiente en std::forward<UTypes>(args).
  • Esta sobrecarga participa en la resolución de sobrecarga solo si
    • sizeof...(Types) == sizeof...(UTypes),
    • sizeof...(Types) >= 1,
    • std::is_constructible<Ti, Ui>::value es true para todo i, y
    • sea D std::decay<U0>::type(hasta C++20)std::remove_cvref_t<U0>(desde C++20),
      • si sizeof...(Types) == 1, entonces D no es std::tuple, en caso contrario,
      • si sizeof...(Types) == 2 o sizeof...(Types) == 3, entonces o D no es std::allocator_arg_t, o T0 es std::allocator_arg_t.
  • El constructor es explicit si y solo si std::is_convertible<Ui, Ti>::value es false para al menos un i.
(desde C++23)
4-7) Constructor de conversión. Inicializa cada elemento de la tupla con el elemento correspondiente de other.

Formalmente, sea FWD(other) std::forward<decltype(other)>(other), para todo i, inicializa el iésimo elemento de la tupla con std::get<i>(FWD(other)).

  • Esta sobrecarga participa en la resolución de sobrecarga solo si
    • sizeof...(Types) == sizeof...(UTypes),
    • std::is_constructible_v<Ti, decltype(std::get<i>(FWD(other)))> es true para todo i, y
    • o bien
      • sizeof...(Types) no es 1, o
      • (cuando Types... se expande a T y UTypes... se expande a U) std::is_convertible_v<decltype(other), T>, std::is_constructible_v<T, decltype(other)>, y std::is_same_v<T, U> son todos false.
  • Estos constructores son explicit si y solo si std::is_convertible_v<decltype(std::get<i>(FWD(other))), Ti> es false para al menos un i.
  • Estos constructores se definen como eliminados si la inicialización de cualquier elemento que sea una referencia lo vinculara a un objeto temporal.
(desde C++23)
8-11) Constructor de par. Construye una tupla de 2 elementos con cada elemento construido a partir del elemento correspondiente de p.

Formalmente, sea FWD(p) std::forward<decltype(p)>(p), inicializa el primer elemento con std::get<0>(FWD(p)) y el segundo elemento con std::get<1>(FWD(p)).

  • Esta sobrecarga participa en la resolución de sobrecarga solo si
    • sizeof...(Types) == 2,
    • std::is_constructible_v<T0, decltype(std::get<0>(FWD(p)))> es true, y
    • std::is_constructible_v<T1, decltype(std::get<1>(FWD(p)))> es true.
  • El constructor es explicit si y solo si std::is_convertible_v<decltype(std::get<0>(FWD(p))), T0> o std::is_convertible_v<decltype(std::get<1>(FWD(p))), T1> es false.
  • Estos constructores se definen como eliminados si la inicialización de cualquier elemento que sea una referencia lo vinculara a un objeto temporal.
(desde C++23)
12) tuple-like constructor. Construye una tupla con cada elemento construido a partir del elemento correspondiente de u.

Formalmente, para todo i, inicializa el iésimo elemento de la tupla con std::get<i>(std::forward<UTuple>(u)).

  • Esta sobrecarga participa en la resolución de sobrecarga solo si
    • std::same_as<std::remove_cvref_t<UTuple>, std::tuple> es false,
    • std::remove_cvref_t<UTuple> no es una especialización de std::ranges::subrange,
    • sizeof...(Types) es igual a std::tuple_size_v<std::remove_cvref_t<UTuple>>,
    • std::is_constructible_v<Ti, decltype(std::get<i>(std::forward<UTuple>(u)))> es true para todo i, y
    • o bien
      • sizeof...(Types) no es 1, o
      • (cuando Types... se expande a T) std::is_convertible_v<UTuple, T> y std::is_constructible_v<T, UTuple> son ambos false.
  • Este constructor se define como eliminado si la inicialización de cualquier elemento que sea una referencia lo vinculara a un objeto temporal.
13) Constructor de copia definido implícitamente. Inicializa cada elemento de la tupla con el elemento correspondiente de other.
  • Este constructor es constexpr si cada operación que realiza es constexpr. Para la tupla vacía std::tuple<>, es constexpr.
  • std::is_copy_constructible<Ti>::value debe ser true para todo i, en caso contrario el comportamiento no está definido(hasta C++20)el programa está mal formado(desde C++20).
14) Constructor de movimiento definido implícitamente. Para todo i, inicializa el iésimo elemento de la tupla con std::forward<Ui>(std::get<i>(other)).
  • Este constructor es constexpr si cada operación que realiza es constexpr. Para la tupla vacía std::tuple<>, es constexpr.
  • std::is_move_constructible<Ti>::value debe ser true para todo i, en caso contrario el comportamiento no está definido(hasta C++20)esta sobrecarga no participa en la resolución de sobrecarga(desde C++20).
15-28) Idéntico a (1-14) excepto que cada elemento se crea mediante construcción con uso-asignador, es decir, el objeto Asignador a se pasa como un argumento adicional al constructor de cada elemento para el cual std::uses_allocator<Ui, Alloc>::value es true.

Parámetros

args - valores utilizados para inicializar cada elemento de la tupla
other - la tupla de valores utilizados para inicializar cada elemento de la tupla
p - el par de valores utilizados para inicializar ambos elementos de la 2-tupla
u - el tuple-like objeto de valores utilizados para inicializar cada elemento de la tupla
a - el asignador a utilizar en la construcción uses-allocator

Notas

Los constructores condicionalmente explícitos hacen posible construir una tupla en contexto de inicialización por copia usando sintaxis de inicialización de lista:

std::tuple<int, int> foo_tuple() 
{
    // return {1, -1};             // Error antes de N4387
    return std::make_tuple(1, -1); // Siempre funciona
}

Tenga en cuenta que si algún elemento de la lista no es convertible implícitamente al elemento correspondiente de la tupla destino, los constructores se vuelven explícitos:

using namespace std::chrono;
void launch_rocket_at(std::tuple<hours, minutes, seconds>);
launch_rocket_at({hours(1), minutes(2), seconds(3)}); // CORRECTO
launch_rocket_at({1, 2, 3}); // Error: int no es convertible implícitamente a duration
launch_rocket_at(std::tuple<hours, minutes, seconds>{1, 2, 3}); // CORRECTO

Ejemplo

#include <iomanip>
#include <iostream>
#include <memory>
#include <string>
#include <string_view>
#include <tuple>
#include <type_traits>
#include <vector>
// función auxiliar para imprimir un vector a un flujo
template<class Os, class T>
Os& operator<<(Os& os, std::vector<T> const& v)
{
    os << '{';
    for (auto i{v.size()}; const T& e : v)
        os << e << (--i ? "," : "");
    return os << '}';
}
template<class T>
void print_single(T const& v)
{
    if constexpr (std::is_same_v<T, std::decay_t<std::string>>)
        std::cout << std::quoted(v);
    else if constexpr (std::is_same_v<std::decay_t<T>, char>)
        std::cout << "'" << v << "'";
    else
        std::cout << v;
}
// función auxiliar para imprimir una tupla de cualquier tamaño
template<class Tuple, std::size_t N>
struct TuplePrinter
{
    static void print(const Tuple& t)
    {
        TuplePrinter<Tuple, N - 1>::imprimir(t);
        std::cout << ", ";
        print_single(std::get<N - 1>(t));
    }
};
template<class Tuple>
struct TuplePrinter<Tuple, 1>
{
    static void print(const Tuple& t)
    {
        print_single(std::get<0>(t));
    }
};
template<class... Args>
void print(std::string_view message, const std::tuple<Args...>& t)
{
    std::cout << message << " (";
    TuplePrinter<decltype(t), sizeof...(Args)>::imprimir(t);
    std::cout << ")\n";
}
// fin función auxiliar
int main()
{
    std::tuple<int, std::string, double> t1;
    print("Inicializado con valor, t1:", t1);
    std::tuple<int, std::string, double> t2{42, "Prueba", -3.14};
    print("Inicializado con valores, t2:", t2);
    std::tuple<char, std::string, int> t3{t2};
    print("Convertido implícitamente, t3:", t3);
    std::tuple<int, double> t4{std::make_pair(42, 3.14)};
    print("Construido a partir de un par, t4:", t4);
    // dado Allocator my_alloc con un constructor de un solo argumento
    // my_alloc(int); use my_alloc(1) to allocate 5 ints in a vector
    using my_alloc = std::allocator<int>;
    std::vector<int, my_alloc> v{5, 1, my_alloc{/* 1 */}};
    // usar my_alloc(2) para asignar 5 enteros en un vector en una tupla
    std::tuple<int, std::vector<int, my_alloc>, double> t5
        {std::allocator_arg, my_alloc{/* 2 */}, 42, v, -3.14};
    print("Construido con asignador, t5:", t5);
}

Salida posible:

Inicializado por valor, t1: (0, "", 0)
Inicializado con valores, t2: (42, "Test", -3.14)
Conversión implícita, t3: ('*', "Test", -3)
Construido desde un par, t4: (42, 3.14)
Construido con asignador, t5: (42, {1,1,1,1,1}, -3.14)

Informes de defectos

Los siguientes informes de defectos que modifican el comportamiento se aplicaron retroactivamente a los estándares de C++ publicados anteriormente.

DR Aplicado a Comportamiento publicado Comportamiento correcto
LWG 2510 C++11 el constructor por defecto era implícito hecho condicionalmente-explícito
LWG 3121 C++11 el constructor de tupla de 1 elemento podría verificar recursivamente las restricciones;
allocator_arg_t argumento generaba ambigüedad
restringido adicionalmente
el constructor
LWG 3158 C++11 el constructor uses-allocator correspondiente
al constructor por defecto era implícito
hecho condicionalmente-explícito
LWG 3211 C++11 si el constructor por defecto de
tuple<> era trivial no estaba especificado
requerido ser trivial
LWG 4045 C++23 tuple-like constructor podría potencialmente crear referencias colgantes definido como eliminado
N4387 C++11 algunos constructores eran explícitos, impidiendo comportamientos útiles la mayoría de constructores hechos
condicionalmente-explícitos

Véase también

asigna el contenido de un tuple a otro
(función miembro pública)
(C++11)
crea un objeto tuple del tipo definido por los tipos de argumento
(plantilla de función)
(C++11)
crea un tuple de referencias a lvalue o desempaqueta un tuple en objetos individuales
(plantilla de función)
crea un tuple de forwarding references
(plantilla de función)
construye un nuevo pair
(función miembro pública de std::pair<T1,T2> )