Namespaces
Variants

std::variant<Tipos...>::variant

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 de programa
Funciones variádicas
Soporte de corrutinas (C++20)
Soporte de contratos (C++26)
Comparación de tres vías
(C++20)
(C++20)(C++20)(C++20)    
(C++20)(C++20)(C++20)

Utilidades generales
Operadores relacionales (obsoleto en C++20)
 
 
constexpr variant() noexcept(/* see below */);
(1) (desde C++17)
constexpr variant( const variant& other );
(2) (desde C++17)
constexpr variant( variant&& other ) noexcept(/* see below */);
(3) (desde C++17)
template< class T >
constexpr variant( T&& t ) noexcept(/* see below */);
(4) (desde C++17)
template< class T,
          class... Args >
constexpr explicit variant( std::in_place_type_t<T>,
                            Args&&... args );
(5) (desde C++17)
template< class T,
          class U,
          class... Args >
constexpr explicit variant( std::in_place_type_t<T>,
                            std::initializer_list<U> il,
                            Args&&... args );
(6) (desde C++17)
template< std::size_t I,
          class... Args >
constexpr explicit variant( std::in_place_index_t<I>,
                            Args&&... args );
(7) (desde C++17)
template< std::size_t I,
          class U,
          class... Args >
constexpr explicit variant( std::in_place_index_t<I>,
                            std::initializer_list<U> il,
                            Args&&... args );
(8) (desde C++17)

Construye un nuevo objeto variant.

1) Constructor por defecto. Construye un variant que contiene el valor inicializado por valor de la primera alternativa (index() es cero).
  • Este constructor es constexpr si y solo si la inicialización por valor del tipo alternativo T_0 cumpliría los requisitos de una función constexpr.
  • Esta sobrecarga participa en la resolución de sobrecarga solo si std::is_default_constructible_v<T_0> es true.
2) Constructor de copia. Si other no está sin valor por excepción, construye un variant que contiene la misma alternativa que other e inicializa directamente el valor contenido con *std::get_if<other.index()>(std::addressof(other)). De lo contrario, inicializa una variante sin valor por excepción.
  • Este constructor se define como eliminado a menos que std::is_copy_constructible_v<T_i> sea true para todos T_i en Types....
  • Es trivial si std::is_trivially_copy_constructible_v<T_i> es true para todos T_i en Types....
3) Constructor de movimiento. Si other no está sin valor por excepción, construye un variant que contiene la misma alternativa que other e inicializa directamente el valor contenido con std::move(*std::get_if<other.index()>(std::addressof(other))). De lo contrario, inicializa una variante sin valor por excepción.
  • Esta sobrecarga participa en la resolución de sobrecarga solo si std::is_move_constructible_v<T_i> es true para todos T_i en Types....
  • Es trivial si std::is_trivially_move_constructible_v<T_i> es true para todos T_i en Types....
4) Constructor de conversión. Construye un variant que contiene el tipo alternativo T_j que sería seleccionado por resolución de sobrecarga para la expresión F(std::forward<T>(t)) si hubiera una sobrecarga de una función imaginaria F(T_i) para cada T_i en Types..., excepto que las conversiones restrictivas no se consideran.

Formalmente:

  • Una sobrecarga F(T_i) solo se considera si la declaración T_i x[] = { std::forward<T>(t) }; es válida para alguna variable inventada x.
Inicializa directamente el valor contenido como si fuera por inicialización directa no de lista desde std::forward<T>(t).
  • Esta sobrecarga participa en la resolución de sobrecarga solo si
    • sizeof...(Types) > 0,
    • std::decay_t<T>(hasta C++20)std::remove_cvref_t<T>(desde C++20) no es del mismo tipo que variant, ni una especialización de std::in_place_type_t, ni una especialización de std::in_place_index_t,
    • std::is_constructible_v<T_j, T> es true,
    • y la expresión F(std::forward<T>(t)) (con F siendo el conjunto mencionado de funciones imaginarias) está bien formada.
  • Este constructor es un constructor constexpr si el constructor seleccionado de T_j es un constructor constexpr.
std::variant<std::string> v("abc"); // OK
std::variant<std::string, std::string> w("abc"); // ill-formed
std::variant<std::string, const char*> x("abc"); // OK, chooses const char*
std::variant<std::string, bool> y("abc"); // OK, chooses string; bool is not a candidate
std::variant<float, long, double> z = 0; // OK, holds long
                                         // float and double are not candidates
5) Construye un variant con la alternativa especificada T e inicializa el valor contenido con los argumentos std::forward<Args>(args)....
  • Si el constructor seleccionado de T es un constructor constexpr, este constructor también es un constructor constexpr.
  • Esta sobrecarga participa en la resolución de sobrecarga solo si hay exactamente una ocurrencia de T en Types... y std::is_constructible_v<T, Args...> es true.
6) Construye un variant con la alternativa especificada T e inicializa el valor contenido con los argumentos il, std::forward<Args>(args)....
  • Si el constructor seleccionado de T es un constructor constexpr, este constructor también es un constructor constexpr.
  • Esta sobrecarga participa en la resolución de sobrecarga solo si hay exactamente una ocurrencia de T en Types... y std::is_constructible_v<T, initializer_list<U>&, Args...> es true.
7) Construye un variant con la alternativa T_i especificada por el índice I e inicializa el valor contenido con los argumentos std::forward<Args>(args)....
  • Si el constructor seleccionado de T_i es un constructor constexpr, este constructor también es un constructor constexpr.
  • Esta sobrecarga participa en la resolución de sobrecarga solo si I < sizeof...(Types) y std::is_constructible_v<T_i, Args...> es true.
8) Construye un variant con la alternativa T_i especificada por el índice I e inicializa el valor contenido con los argumentos il, std::forward<Args>(args)....
  • Si el constructor seleccionado de T_i es un constructor constexpr, este constructor también es un constructor constexpr.
  • Esta sobrecarga participa en la resolución de sobrecarga solo si I < sizeof...(Types) y std::is_constructible_v<T_i, std::initializer_list<U>&, Args...> es true.

Parámetros

other - otro objeto variant cuyo valor contenido copiar/mover
t - valor para inicializar el valor contenido
args... - argumentos para inicializar el valor contenido
il - lista de inicialización para inicializar el valor contenido

Excepciones

1) Puede lanzar cualquier excepción lanzada por la inicialización de valor de la primera alternativa.
noexcept especificación:
2) Puede lanzar cualquier excepción lanzada por la inicialización directa de cualquier T_i en Types... .
3) Puede lanzar cualquier excepción lanzada por la construcción por movimiento de cualquier T_i en Types... .
noexcept especificación:
noexcept ( ( std:: is_nothrow_move_constructible_v < Types > && ... ) )
4) Puede lanzar cualquier excepción lanzada por la inicialización de la alternativa seleccionada T_j .
noexcept especificación:
noexcept ( std:: is_nothrow_constructible_v < T_j, T > )
5-8) Puede lanzar cualquier excepción lanzada al llamar al constructor seleccionado de la alternativa seleccionada.

Notas

MSVC STL inicialmente trató P0608R3 como un cambio en C++20. A partir de VS 2022 17.12, MSVC STL también trata P0608R3 como un informe de defectos contra C++17.

Ejemplo

#include <cassert>
#include <iostream>
#include <string>
#include <variant>
#include <vector>
using vector_t = std::vector<int>;
auto& operator<<(auto& out, const vector_t& v)
{
    out << "{ ";
    for (int e : v)
        out << e << ' ';
    return out << '}';
}
int main()
{
    // inicializa por valor la primera alternativa
    std::variant<int, std::string> var0;
    assert(std::holds_alternative<int>(var0) and
           var0.index() == 0 and
           std::get<int>(var0) == 0);
    // inicializa la primera alternativa con std::string{"STR"};
    std::variant<std::string, int> var1{"STR"};
    assert(var1.index() == 0);
    std::cout << "1) " << std::get<std::string>(var1) << '\n';
    // inicializa la segunda alternativa con int == 42;
    std::variant<std::string, int> var2{42};
    assert(std::holds_alternative<int>(var2));
    std::cout << "2) " << std::get<int>(var2) << '\n';
    // inicializa la primera alternativa con std::string{4, 'A'};
    std::variant<std::string, vector_t, float> var3
    {
        std::in_place_type<std::string>, 4, 'A'
    };
    assert(var3.index() == 0);
    std::cout << "3) " << std::get<std::string>(var3) << '\n';
    // inicializa la segunda alternativa con std::vector{1,2,3,4,5};
    std::variant<std::string, vector_t, char> var4
    {
        std::in_place_type<vector_t>, {1, 2, 3, 4, 5}
    };
    assert(var4.index() == 1);
    std::cout << "4) " << std::get<vector_t>(var4) << '\n';
    // inicializa la primera alternativa con std::string{"ABCDE", 3};
    std::variant<std::string, vector_t, bool> var5 {std::in_place_index<0>, "ABCDE", 3};
    assert(var5.index() == 0);
    std::cout << "5) " << std::get<std::string>(var5) << '\n';
    // inicializa la segunda alternativa con std::vector(4, 42);
    std::variant<std::string, vector_t, char> var6 {std::in_place_index<1>, 4, 42};
    assert(std::holds_alternative<vector_t>(var6));
    std::cout << "6) " << std::get<vector_t>(var6) << '\n';
}

Salida:

1) STR
2) 42
3) AAAA
4) { 1 2 3 4 5 }
5) ABC
6) { 42 42 42 42 }

Informes de defectos

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

DR Aplicado a Comportamiento publicado Comportamiento correcto
LWG 2901 C++17 constructores conscientes del asignador proporcionados pero
variant no puede soportar adecuadamente asignadores
constructores eliminados
P0739R0 C++17 la plantilla del constructor de conversión interactúa
deficientemente con la deducción de argumentos de plantilla de clase
restricción añadida
LWG 3024 C++17 el constructor de copia no participa en la
resolución de sobrecarga si algún tipo miembro no es copiable
definido como eliminado en su lugar
P0602R4 C++17 los constructores de copia/movimiento pueden no ser
triviales incluso si los constructores subyacentes son triviales
requerido propagar trivialidad
P0608R3 C++17 el constructor de conversión ensambla ciegamente
un conjunto de sobrecarga, conduciendo a conversiones no intencionadas
conversiones de estrechamiento y booleanas no consideradas
P1957R2 C++17 el constructor de conversión para bool no permitía
conversión implícita
La conversión de puntero a bool es de estrechamiento y
el constructor de conversión no tiene
excepción para bool