2 votes

C++ sépare les structures en "groupes" mais permet à `std::variant` de voir toutes les structures à travers les "groupes".

Voir le code ci-dessous.

J'ai 3 struct s ( A , B y C ) définis dans 2 groupes (en réalité, j'en ai beaucoup plus). Les groupes servent à fournir un contexte dans le domaine réel que je modélise. Ces groupes sont mis en œuvre par l'intermédiaire de deux std::variant s ( Group1 y Group2 ).

J'ai une fonction qui peut renvoyer n'importe lequel des éléments sous-jacents suivants struct s.

Pour fournir un seul type de retour pour la fonction, je crée un troisième type de retour, le std::variant ( AllGroups ) de mes deux variantes initiales ( Group1 y Group2 ).

Cependant, mon problème est le suivant AllGroups ne peut pas voir A , B o C , seulement Group1 y Group2 .

Existe-t-il un moyen de conserver les structures définies avec une sorte de groupe, mais aussi de les regrouper en une seule ? std::variant pour le type de retour de la fonction ?

#include <variant>
#include <iostream>

struct A{}; struct B{};
using Group1 = std::variant<A, B>;

struct C{};
using Group2 = std::variant<C>;

using AllGroups = std::variant<Group1, Group2>;

AllGroups getObject()
{
    A a;     // Simple logic for the general question
    AllGroups ret(a);
    return ret;
}

int main()
{
    AllGroups ret = getObject();

    // Here i'd like to check for the individual structs, not Group1 and Group2
    // However I get a compiler error because the AllVariant can only see Group1 and Group2

    std::cout << std::holds_alternative<A>(ret) << std::endl;
}

4voto

SergeyA Points 2159

Voici comment vous pouvez créer un trait qui produit le type que vous souhaitez - une combinaison des types alternatifs de la variante. Contrairement aux autres réponses, cela fonctionne avec plus de deux variantes jointes ;)

#include <variant>

template<class Variant1, class Variant2, class... Variants> 
struct variant_cat;

template<class... Var1, class... Var2>
struct variant_cat<std::variant<Var1...>, std::variant<Var2...>>
{
    using type = std::variant<Var1..., Var2...>;
};

template<class... Var1, class... Var2, class... Variants>
struct variant_cat<std::variant<Var1...>, std::variant<Var2...>, Variants...>
{
    using type = typename variant_cat<std::variant<Var1..., Var2...>, Variants...>::type;
};

template<class... A>
using variant_cat_t = variant_cat<A...>::type;

// Usage:
variant_cat_t<std::variant<int, char>, std::variant<double, float>, std::variant<std::nullptr_t>> Result;

2voto

tobi303 Points 2932

Vous pouvez utiliser un trait pour combiner std::variant<A...> con std::variant<B...> pour obtenir std::variant<A...,B...> :

#include <variant>
#include <iostream>

struct A{}; struct B{};
using Group1 = std::variant<A, B>;

struct C{};
using Group2 = std::variant<C>;

template <typename T1,typename T2> struct combine_variants;

template <typename... A,typename... B>
struct combine_variants<std::variant<A...>,std::variant<B...>> {
    using type = std::variant<A...,B...>;
};

using AllGroups = combine_variants<Group1, Group2>::type;

AllGroups getObject()
{
    A a;     // Simple logic for the general question
    AllGroups ret(a);
    return ret;
}

int main()
{
    AllGroups ret = getObject();

    std::cout << std::holds_alternative<A>(ret) << std::endl;
}

Démonstration en direct

2voto

NathanOliver Points 10062

Voici une autre approche pour concaténer deux types de variantes afin d'obtenir un type fusionné

template <typename... Ts, typename... Us>
auto variant_concat(std::variant<Ts...>, std::variant<Us...>) -> std::variant<Ts..., Us...>;

template <typename V1, typename V2>
using variant_concat_t = decltype(variant_concat(std::declval<V1>(), std::declval<V2>()));

et vous l'utiliserez comme

using AllGroups = variant_concat_t<Group1, Group2>;

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X