Namespaces
Variants

std:: visit

From cppreference.net
Utilities library
Défini dans l'en-tête <variant>
template < class Visitor, class ... Variants >
constexpr /* voir ci-dessous */ visit ( Visitor && v, Variants && ... values ) ;
(1) (depuis C++17)
template < class R, class Visitor, class ... Variants >
constexpr R visit ( Visitor && v, Variants && ... values ) ;
(2) (depuis C++20)
Modèles d'aide
template < class ... Ts >
auto && as - variant ( std:: variant < Ts... > & value ) ;
(3) ( exposition uniquement* )
template < class ... Ts >
auto && as - variant ( const std:: variant < Ts... > & value ) ;
(4) ( exposition uniquement* )
template < class ... Ts >
auto && as - variant ( std:: variant < Ts... > && value ) ;
(5) ( exposition uniquement* )
template < class ... Ts >
auto && as - variant ( const std:: variant < Ts... > && value ) ;
(6) ( exposition uniquement* )

Applique le visiteur v (un Callable pouvant être appelé avec n'importe quelle combinaison de types des Variants) aux Variants values .

Soit VariantBases comme decltype ( as-variant ( std:: forward < Variants > ( values ) ) ... (un pack de sizeof... ( Variants ) types) :

1) Appelle v comme si par

INVOKE ( std:: forward < Visitor > ( v ) ,
std :: get < indices > ( std:: forward < VariantBases > ( values ) ) ... )
,

indices est as-variant ( values ) . index ( ) ... .
2) Appelle v comme si par

INVOKE<R> ( std:: forward < Visitor > ( v ) ,
std :: get < indices > ( std:: forward < VariantBases > ( values ) ) ... )
,

indices est as-variant ( values ) . index ( ) ... .

Ces surcharges participent à la résolution de surcharge seulement si chaque type dans VariantBases est un type valide. Si l'expression désignée par INVOKE ou INVOKE<R> (depuis C++20) est invalide, ou si les résultats de INVOKE ou INVOKE<R> (depuis C++20) ont des types ou des catégories de valeur différents pour différents indices , le programme est mal formé.

3-6) Les modèles de fonctions d'exposition uniquement as-variant acceptent une valeur dont le type peut être déduit pour std:: variant < Ts... > (c'est-à-dire soit std:: variant < Ts... > soit un type dérivé de std:: variant < Ts... > ), et retournent la valeur std::variant avec la même qualification const et catégorie de valeur.
3,4) Retourne value .
5,6) Retourne std :: move ( value ) .

Table des matières

Paramètres

v - un Callable qui accepte chaque alternative possible de chaque variant dans Variants
values - liste de variants à passer au visiteur

Valeur de retour

1) Le résultat de l'opération INVOKE . Le type de retour est le type obtenu en appliquant decltype au résultat.
2) Rien si R est (éventuellement qualifié cv) void ; sinon le résultat de l'opération INVOKE<R> .
3-6) Une valeur std::variant convertie à partir de value .

Exceptions

Lance std::bad_variant_access si as-variant ( value_i ) . valueless_by_exception ( ) est true pour n'importe quel variant value_i dans values .

Complexité

Lorsque le nombre de variantes est zéro ou un, l'invocation de l'objet appelable est implémentée en temps constant ; c'est-à-dire qu'elle ne dépend pas du nombre de types pouvant être stockés dans la variant.

Si le nombre de variantes est supérieur à un, l'invocation de l'objet appelable n'a aucune exigence de complexité.

Notes

Soit n égal à ( 1 * ... * std:: variant_size_v < std:: remove_reference_t < VariantBases >> ) , les implémentations génèrent généralement une table équivalente à un tableau (éventuellement multidimensionnel) de n pointeurs de fonctions pour chaque spécialisation de std::visit , ce qui est similaire à l'implémentation des fonctions virtuelles .

Les implémentations peuvent également générer une instruction switch avec n branches pour std::visit (par exemple, l'implémentation MSVC STL utilise une instruction switch lorsque n n'est pas supérieur à 256).

Sur les implémentations typiques, la complexité temporelle de l'invocation de v peut être considérée comme équivalente à celle de l'accès à un élément dans un tableau (éventuellement multidimensionnel) ou à l'exécution d'une instruction switch.

Macro de test de fonctionnalité Valeur Std Fonctionnalité
__cpp_lib_variant 202102L (C++23)
(DR17)
std::visit pour les classes dérivées de std::variant

Exemple

#include <iomanip>
#include <iostream>
#include <string>
#include <type_traits>
#include <variant>
#include <vector>
// la variante à visiter
using value_t = std::variant<int, long, double, std::string>;
// type d'assistant pour le visiteur #4
template<class... Ts>
struct overloaded : Ts... { using Ts::operator()...; };
// guide de déduction explicite (non nécessaire à partir de C++20)
template<class... Ts>
overloaded(Ts...) -> overloaded<Ts...>;
int main()
{
    std::vector<value_t> vec = {10, 15l, 1.5, "bonjour"};
    for (auto& v: vec)
    {
        // 1. visiteur void, appelé uniquement pour les effets secondaires (ici, pour les E/S)
        std::visit([](auto&& arg){ std::cout << arg; }, v);
        // 2. visiteur retournant une valeur, démontre l'idiome de retourner une autre variante
        value_t w = std::visit([](auto&& arg) -> value_t { return arg + arg; }, v);
        // 3. visiteur de correspondance de type : une lambda qui traite chaque type différemment
        std::cout << ". Après doublement, la variante contient ";
        std::visit([](auto&& arg)
        {
            using T = std::decay_t<decltype(arg)>;
            if constexpr (std::is_same_v<T, int>)
                std::cout << "int avec valeur " << arg << '\n';
            else if constexpr (std::is_same_v<T, long>)
                std::cout << "long avec valeur " << arg << '\n';
            else if constexpr (std::is_same_v<T, double>)
                std::cout << "double avec valeur " << arg << '\n';
            else if constexpr (std::is_same_v<T, std::string>)
                std::cout << "std::string avec la valeur " << std::quoted(arg) << '\n';
            else
                static_assert(false, "visiteur non exhaustif !");
        }, w);
    }
    for (auto& v: vec)
    {
        // 4. un autre visiteur de correspondance de types : une classe avec 3 operator() surchargés
        // Note: Le template `(auto arg)` operator() se liera à `int` et `long`
        //       dans ce cas, mais en son absence l'opérateur `(double arg)` operator()
        //       *va également* se lier à `int` et `long` car les deux sont implicitement
        //       convertible en double. Lors de l'utilisation de cette forme, il faut prendre soin
        //       que les conversions implicites sont gérées correctement.
        std::visit(overloaded{
            [](auto arg) { std::cout << arg << ' '; },
            [](double arg) { std::cout << std::fixed << arg << ' '; },
            [](const std::string& arg) { std::cout << std::quoted(arg) << ' '; }
        }, v);
    }
}

Sortie :

10. Après doublement, variant contient int avec valeur 20
15. Après doublement, variant contient long avec valeur 30
1.5. Après doublement, variant contient double avec valeur 3
hello. Après doublement, variant contient std::string avec valeur "hellohello"
10 15 1.500000 "hello"

Rapports de défauts

Les rapports de défauts modifiant le comportement suivants ont été appliqués rétroactivement aux normes C++ précédemment publiées.

DR Appliqué à Comportement publié Comportement correct
LWG 2970 C++17 le type de retour de la surcharge (1) ne préservait pas la
catégorie de valeur du résultat de l'opération INVOKE
préserve
LWG 3052
( P2162R2 )
C++17 les effets n'étaient pas spécifiés si un type
dans Variants n'est pas un std::variant
spécifié

Voir aussi

(C++26)
appelle le foncteur fourni avec l'argument contenu par le variant
(fonction membre publique)
échange avec un autre variant
(fonction membre publique)