En C ++, comment faire une variante qui peut contenir un vecteur de variante de même?

voix
2

Je une essayer de faire une std :: variante qui peut contenir un vecteur de la même variante:

class ScriptParameter;
using ScriptParameter = std::variant<bool, int, double, std::string, std::vector<ScriptParameter> >;

Je reçois redéfinition ParamètreScript. Il pense qu'il est peut-être parce qu'un paramètre de modèle ne peut pas être déclaré avant?

Est-il un moyen de parvenir à une variante qui pourrait également contenir une série de variantes mêmes typées?

Créé 27/11/2018 à 15:18
source utilisateur
Dans d'autres langues...                            


3 réponses

voix
5

Depuis la déclaration de l' avant dit ScriptParameterest une classe, vous ne pouvez pas utiliser usingalias. Cependant, rien est intrinsèquement mauvais ici, puisque vectorseulement un pointeur, il n'y a pas de réelle dépendance circulaire.

Vous pouvez utiliser l'héritage:

class ScriptParameter;
class ScriptParameter
    : public std::variant<bool, int, double, std::string, std::vector<ScriptParameter> >
{
public:
    using base = std::variant<bool, int, double, std::string, std::vector<ScriptParameter> >;
    using base::base;
    using base::operator=;
};

int main() {    
    ScriptParameter sp{"hello"};
    sp = 1.0;
    std::vector<ScriptParameter> vec;
    sp = vec;    
    std::cout << sp.index() << "\n";  
}
Créé 27/11/2018 à 15:25
source utilisateur

voix
1

Je ne suis pas sûr une définition récursive est logique dans ce cas. Il permet arbitrairement de nombreux vecteurs imbriqués dans un seul ScriptParameter. (Essentiellement , nous disons qu'un paramètre de script est soit une valeur unique ou toute une forêt de valeurs.) Fractionnement la définition en deux pourrait mieux fonctionner:

// Represents the value of a single parameter passed to a script
using ScriptParameter = std::variant<bool, int, double, std::string>;

// Represents a collection of one or many script parameters
using ScriptParameterSet = std::variant<ScriptParameter, std::vector<ScriptParameter>>;

Par ailleurs, si l'objectif est ici de définir un paramètre comme l'un d'un ensemble de choix, plus un vecteur de ces mêmes choix, vous pouvez essayer un peu de magie modèle:

template <class T, class U> struct variant_concat;

template <class... T, class U> struct variant_concat<std::variant<T...>, U>
{
  using type = std::variant<T..., U>;
};

template <class T, class U> using variant_concat_t = typename variant_concat<T, U>::type;

using PrimitiveScriptParameter = std::variant<bool, int, double, std::string>;

using ScriptParameter = variant_concat_t<
  PrimitiveScriptParameter,
  std::vector<PrimitiveScriptParameter>>;

Cela devrait répondre aux préoccupations de la facilité d'utilisation de Légèreté ci-dessous.

Créé 27/11/2018 à 15:48
source utilisateur

voix
0

Utiliser le niveau de type opérateur en virgule fixe .

#include <vector>
#include <variant>
#include <string>

// non-recursive definition 
template<class T>
using Var = std::variant<int, bool, double, std::string, std::vector<T>>;

// tie the knot
template <template<class> class K>
struct Fix : K<Fix<K>>
{
   using K<Fix>::K;
};

using ScriptParameter = Fix<Var>;

// usage example    
int main()
{
    using V = std::vector<ScriptParameter>;
    ScriptParameter k {V{1, false, "abc", V{2, V{"x", "y"}, 3.0}}};
}
Créé 27/11/2018 à 16:46
source utilisateur

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more