std::variant<Types...>::variant
De cppreference.com
constexpr variant() noexcept(/* véase más abajo */);
|
(1) | (desde C++17) |
constexpr variant( const variant& other );
|
(2) | (desde C++17) |
constexpr variant( variant&& other ) noexcept(/* véase más abajo */);
|
(3) | (desde C++17) |
template< class T >
constexpr variant( T&& t ) noexcept(/* véase más abajo */);
|
(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 variante.
1) Constructor por defecto. Construye un variante que mantiene el valor inicializado por valor de la primera alternativa cuyo subíndice (index()) es cero.
- Este constructor es
constexprsi y solo si la inicialización de un valor del tipo de la alternativa T_0 satisfaría los requisitos de una función constexpr. - Esta sobrecarga solo participa en la resolución de sobrecargas si
std::is_default_constructible_v<T_0>estrue.
2) Constructor de copia. Si
other no es valueless_by_exception, construye un variante que mantiene la misma alternativa que other y directamente inicializa el valor contenido con std::get<other.index()>(other). De lo contrario, inicializa un variante sin valor debido a una excepción (valueless_by_exception).
- Este constructor se define como eliminado a menos que
std::is_copy_constructible_v<T_i>seatruepara todaT_ienTypes.... - Es trivial si
std::is_trivially_copy_constructible_v<T_i>estruepara todaT_ienTypes....
3) Constructor de movimiento. Si
other no es valueless_by_exception, construye un variante que mantiene la misma alternativa que other y directamente inicializa el valor contenido con std::get<other.index()>(std::move(other)). De lo contrario, inicializa un variante sin valor debido a una excepción (valueless_by_exception).
- Esta sobrecarga solo participa en la resolución de sobrecargas si
std::is_move_constructible_v<T_i>estruepara todaT_ienTypes.... - Es trivial si
std::is_trivially_move_constructible_v<T_i>estruepara todaT_ienTypes....
4) Constructor de conversión. Construye un variante que mantiene la alternativa de tipo
T_j que se seleccionaría por la resolución de sobrecarga para la expresión F(std::forward<T>(t)) si hubiera una sobrecarga de la función imaginaria F(T_i) para cada T_i de Types... en ámbito al mismo tiempo, excepto que:
- Una sobrecarga
F(T_i)solamente se considera si la declaraciónT_i x[] = { std::forward<T>(t) };es válida para alguna variable inventadax;
- Una sobrecarga
Directamente inicializa el valor contenido como si fuera por inicialización directa de no lista a partir de
std::forward<T>(t).
- Esta sobrecarga solo participa en la resolución de sobrecargas si
sizeof...(Types) > 0,std::decay_t<U>(hasta C++20)std::remove_cvref_t<U>(desde C++20) no es ni del mismo tipo quevariant, 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>estrue,- y la expresión
F(std::forward<T>(t))(con F siendo el conjunto de funciones imaginarias mencionadas anteriormente) está bien formada.
- Este constructor es un constructor
constexprsi el constructor seleccionado de T_j es un constructorconstexpr.
std::variant<std::string> v("abc"); // de acuerdo
std::variant<std::string, std::string> w("abc"); // mal formado
std::variant<std::string, const char*> x("abc"); // OK, escoge a const char*
std::variant<std::string, bool> y("abc"); // de acuerdo, escoge a string; bool no es un candidato
std::variant<float, long, double> z = 0; // de acuerdo, mantiene un long
// float y double no son candidatos
5) Construye un variante con la alternativa especificada
T e inicializa el valor contenido con los argumentos std::forward<Args>(args)....
- Si el constructor seleccionado de T_j es un constructor
constexpr, este constructor también es un constructorconstexpr. - Esta sobrecarga solo participa en la resolución de sobrecargas si hay exactamente una ocurrencia de T en
Types...ystd::is_constructible_v<T, Args...>estrue.
6) Construye un variante 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 constructorconstexpr. - Esta sobrecarga solo participa en la resolución de sobrecargas si hay exactamente una ocurrencia de T en
Types...ystd::is_constructible_v<T, initializer_list<U>&, Args...>estrue.
7) Construye un variante con la alternativa T_i especificada por el subí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 constructorconstexpr. - Esta sobrecarga solo participa en la resolución de sobrecargas si
I < sizeof...(Types)ystd::is_constructible_v<T_i, Args...>sontrue.
8) Construye un variante con la alternativa T_i especificada por el subí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 constructorconstexpr. - Esta sobrecarga solo participa en la resolución de sobrecargas si
I < sizeof...(Types)ystd::is_constructible_v<T_i, std::initializer_list<U>&, Args...>sontrue.
Parámetros
| other | - | Otro objecto variante cuyo valor contenido hay que copiar o mover. |
| t | - | Valor con el cual inicializar el valor contenido. |
| args... | - | Argumentos con los cuales inicializar el valor contenido. |
| il | - | Lista de inicializadores con la cual inicializar el valor contenido. |
Excepciones
1) Puede lanzar cualquier excepción lanzada por la inicialización de un valor de la primera alternativa.
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.... Especificación noexcept: (desde C++11)
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. 5-8) Puede lanzar cualquier excepción lanzada por llamar al constructor seleccionado de la alternativa seleccionada.
Ejemplo
Ejecuta este código
#include <cassert>
#include <iostream>
#include <string>
#include <variant>
#include <vector>
template <class Os> Os& operator<< (Os& os, const std::vector<int>& v) {
os << "{ ";
for (int e: v) { std::cout << e << ' '; }
return os << "}";
}
int main()
{
{
std::variant<int, std::string> var; // inicializa primera alternativa por valor
assert(std::holds_alternative<int>(var) && var.index() == 0 &&
std::get<int>(var) == 0);
}
{
std::variant<std::string, int> var{"STR"};
// inicializa primera alternativa con std::string{"STR"};
assert(var.index() == 0);
std::cout << "1) " << std::get<std::string>(var) << '\n';
}
{
std::variant<std::string, int> var{42};
// inicializa segunda alternativa con int = 42;
assert(std::holds_alternative<int>(var));
std::cout << "2) " << std::get<int>(var) << '\n';
}
{
std::variant<std::string, std::vector<int>, float> var{
std::in_place_type<std::string>, 4, 'A'};
// inicializa primera alternativa con std::string{4, 'A'};
assert(var.index() == 0);
std::cout << "3) " << std::get<std::string>(var) << '\n';
}
{
std::variant<std::string, std::vector<int>, char> var{
std::in_place_type<std::vector<int>>, {1,2,3,4,5} };
// inicializa segunda alternativa con std::vector{1,2,3,4,5};
assert(var.index() == 1);
std::cout << "4) " << std::get<std::vector<int>>(var) << '\n';
}
{
std::variant<std::string, std::vector<int>, bool> var{
std::in_place_index<0>, "ABCDE", 3};
// inicializa primera alternativa con std::string{"ABCDE", 3};
assert(var.index() == 0);
std::cout << "5) " << std::get<std::string>(var) << '\n';
}
{
std::variant<std::string, std::vector<int>, char> var{
std::in_place_index<1>, 4, 42};
// inicializa segunda alternativa con std::vector(4, 42);
assert(std::holds_alternative<std::vector<int>>(var));
std::cout << "6) " << std::get<std::vector<int>>(var) << '\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 de cambio de comportamiento se aplicaron de manera retroactiva a los estándares de C++ publicados anteriormente.
| ID | Aplicado a | Comportamiento según lo publicado | Comportamiento correcto |
|---|---|---|---|
| LWG 2901 | C++17 | Se proporcionaron constructores conscientes de asignación de memoria, pero variant no puede soportar asignadoresde memoria apropiadamente |
Se eliminaron los constructores |
| P0739R0 | C++17 | La plantilla de constructor de conversión interactúa pobremente con la deducción de argumentos de plantillas de clase |
Se añadió restricción |
| LWG 3024 | C++17 | El constructor de copia no participa en la resolución de sobrecarga si cualquier tipo miembro no es copiable |
En su lugar se definió como eliminado |
| P0602R4 | C++17 | Constructores de copia/movimiento pueden ser no triviales incluso si los constructores subyacentes son triviales |
Se exigió que la trivialidad se propagase |
| P0608R3 | C++17 | Constructor de conversión ciegamente ensambla un conjunto de sobrecargas, lo que conduce a conversiones no deseadas |
No se consideran las conversiones de estrechamiento ni Booleanas |
| P1957R2 | C++17 | Constructor de conversión para bool no permitía conversionesimplícitas |
La conversión de puntero a bool es estrechantey el constructor de conversión no tiene una excepción para bool
|