IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Boost C++ Discussion :

boost make_recursive_variant et recursive_variant_


Sujet :

Boost C++

  1. #1
    Membre du Club
    Profil pro
    Inscrit en
    Octobre 2007
    Messages
    165
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2007
    Messages : 165
    Points : 62
    Points
    62
    Par défaut boost make_recursive_variant et recursive_variant_
    Bonjour à tous,

    J'ai découvert il y a peu les variants de boost et j'ai défini le type suivant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    typedef boost::make_recursive_variant<bool, int, size_t, std::string, time_t, unsigned int, unsigned long long, std::map<std::string, boost::recursive_variant_>, std::vector<std::string>>::type		Value;
    J'utilisais ce type comme par exemple avec une map de type
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    std::map<std::string, Value>
    et où j'accède aux données de la façon suivante
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    	for (const auto &data : datas)	{
    		if (data.second.type() == typeid(bool))										root[data.first] = boost::get<bool>(data.second);
    		else if (data.second.type() == typeid(int))									root[data.first] = boost::get<int>(data.second);
    		else if (data.second.type() == typeid(size_t))								root[data.first] = static_cast<uint64_t>(boost::get<size_t>(data.second));
    		else if (data.second.type() == typeid(std::string))							root[data.first] = boost::get<std::string>(data.second);
    		else if (data.second.type() == typeid(time_t))								root[data.first] = static_cast<int64_t>(boost::get<time_t>(data.second));
    		else if (data.second.type() == typeid(unsigned int))						root[data.first] = boost::get<unsigned int>(data.second);
    		else if (data.second.type() == typeid(unsigned long long))					root[data.first] = boost::get<uint64_t>(data.second);
    		else if (data.second.type() == typeid(std::map<std::string, Value>))		root[data.first] = this->convertDataToJson(boost::get<std::map<std::string, Value>>(data.second));
    		else if (data.second.type() == typeid(std::vector<std::string>))			root[data.first] = this->convertDataToJson(boost::get<std::vector<std::string>>(data.second));
    		else	{
    			Utils::log(Logger::LEVEL::WARN, "Type not found for key [%s]", data.first.c_str());
    		}
    Sauf que par la suite, je me suis rendu compte qu'en plus d'un vector de string, j'ai besoin d'un vector de map<std::string, std::string>. J'ai essayé de modifier mon type comme suit
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    typedef boost::make_recursive_variant<bool, int, size_t, std::string, time_t, unsigned int, unsigned long long, std::map<std::string, boost::recursive_variant_>, std::vector<boost::recursive_variant_>>::type		Value;
    mais quand je tente d'utiliser mon type Value, j'ai une erreur...


    Je m'explique...
    1) J'ai une classe Dto où j'ai 3 méthodes pour ajouter des data
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    class	 Dto
    {
    /* Attributs */
    	...
    	std::map<std::string, Value>				_data;
     
     
    /* Methods */
    public:
    	...
    	/* Setters */
    	void										setData(const std::map<std::string, std::string> &data);
    	void 										setData(const std::pair<std::string, Value> &data);
    	void										setData(const std::string &key, const Value &value);
    2) J'ai une classe EventPlayDoneDto qui hérite de ma classe Dto où je souhaite ajouter une vecteur de strings
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    class EventPlayDoneDto : public Dto
    {
    /* Methods */
    public:
    	...
    	void												setPlayedFiles(const std::vector<std::string> &files);
    };
     
    //----------------------------------
    void											EventPlayDoneDto::setPlayedFiles(const std::vector<std::string> &files)
    //----------------------------------
    {
    	this->setData("files", files);
    }
    Au moment de compiler, j'obtiens l'erreur suivante
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    eventplaydonedto.cpp: In member function ‘void EventPlayDoneDto::setPlayedFiles(const std::vector<std::basic_string<char> >&)’:
    eventplaydonedto.cpp:49:30: error: no matching function for call to ‘EventPlayDoneDto::setData(const char [6], const std::vector<std::basic_string<char> >&)this->setData("files", files);
    Je ne vois pas ce que j'ai raté...

    Est-ce que mon nouveau type Value vous semble correct? et qu'est ce que j'ai pu faire de travers?

  2. #2
    Membre du Club
    Profil pro
    Inscrit en
    Octobre 2007
    Messages
    165
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2007
    Messages : 165
    Points : 62
    Points
    62
    Par défaut
    Je viens de procéder à un test tout simple
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    #include <boost/variant.hpp>
    #include <map>
    #include <vector>
     
    typedef boost::make_recursive_variant<bool, int, size_t, std::string, time_t, unsigned int, unsigned long long, std::map<std::string, boost::recursive_variant_>, std::vector<boost::recursive_variant_>>::type         Value;
     
    int main(int ac, char **av)
    {
            std::vector<std::string>                files;
            files.push_back("1.pcm");
            files.push_back("2.pcm");
     
            std::map<std::string, Value>            tmp;
            tmp.insert(std::pair<std::string, Value>("files", files));
     
            std::vector<Value>                      values;
            values.push_back(tmp);
            return 1;
    }
    Et j'obtiens l'erreur suivante
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    test.cpp:15:57: error: no matching function for call to ‘std::pair<std::basic_string<char>, boost::variant<boost::detail::variant::recursive_flag<bool>, int, long unsigned int, std::basic_string<char, std::char_traits<char>, std::allocator<char> >, long int, unsigned int, long long unsigned int, std::map<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, boost::recursive_variant_, std::less<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, boost::recursive_variant_> > >, std::vector<boost::recursive_variant_, std::allocator<boost::recursive_variant_> > > >::pair(const char [6], std::vector<std::basic_string<char> >&)’
      tmp.insert(std::pair<std::string, Value>("files", files));
    L'ajout de mon vector<std::string> dans ma map ne passe pas...



    Je viens de prendre l'exemple du tutorial
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    typedef boost::make_recursive_variant<
          int
        , std::vector< boost::recursive_variant_ >
        >::type int_tree_t;
     
    std::vector< int_tree_t > subresult;
    subresult.push_back(3);
    subresult.push_back(5);
     
    std::vector< int_tree_t > result;
    result.push_back(1);
    result.push_back(subresult);
    result.push_back(7);
     
    int_tree_t var(result);
    En fait, si je change la variable subresult en std::vector<int>, j'obtiens exactement la même erreur
    Pourquoi est-ce qu'un vecteur/map de mon type variant ne peut pas valoir un vecteur/map d'un type bien défini?

  3. #3
    Invité
    Invité(e)
    Par défaut
    Bonjour,

    Citation Envoyé par m0ul3sh0t Voir le message
    Pourquoi est-ce qu'un vecteur/map de mon type variant ne peut pas valoir un vecteur/map d'un type bien défini?
    Pas exactement.

    Les éléments std::vector<boost::recursive_variant_> sont assimilables à std::vector<Value>. Pas std::vector<bool>, std::vector<std::string>, etc.
    Et quels que soient les types U != T, tu ne peux pas passer directement d'un std::vector<U> à std::vector<T>, même s'il existe une conversion implicite entre U et T.

    Tu dois donc utiliser std::vector<Value> à la place :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    std::vector<Value> files;
    files.emplace_back("1.pcm");
    files.emplace_back("2.pcm");
     
    std::map<std::string, Value> tmp;
    tmp.emplace("files", files); // OK : construction d'un Value à partir d'un std::vector<Value>
    Ou si tu pars d'un std::vector<std::string>, d'abord le convertir en std::vector<Value> :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    void EventPlayDoneDto::setPlayedFiles(const std::vector<std::string> &files)
    {
        setData("files", std::vector<Value>(files.begin(), files.end())); // OK : construction de chaque Value à partir de std::string
    }
    Le même principe s'applique pour std::map.

    Sinon, à la place de tes if/else if, utilise plutôt boost::apply_visitor.
    Dernière modification par Invité ; 25/07/2019 à 17h02.

  4. #4
    Membre du Club
    Profil pro
    Inscrit en
    Octobre 2007
    Messages
    165
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2007
    Messages : 165
    Points : 62
    Points
    62
    Par défaut
    Hum donc en gros, soit je traite uniquement avec des std::vector<Value> soit je reconstruis mon vector au moment d'ajouter mon vector<std::string>. Merci

    Je vais regarder la notion de boost::apply_visitor

  5. #5
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Salut,

    A vrai dire, j'ai un léger problème de compréhension de ton besoin

    Si j'arrive à comprendre pourquoi tu souhaites avoir un variant qui puisse être de type bool, int, unsigned int , string et time_t (*), j'ai beaucoup de mal à imaginer une situation dans laquelle ces types "simples" devraient pouvoir cohabiter avec des types aussi complexes que des std::map<x, y> ou des std::vector<z>.

    C'est surement dut au fait que j'ai, de manière générale, une sainte horreur de la notion même de variant et que je n'y ai recours que lorsque je n'ai pas d'autre choix (lorsque je veux pouvoir sérialiser une configuration complexe, par exemple), en veillant toujours à retomber le plus vite possible sur des données de types clairement définis afin de pouvoir abandonner mes variants.

    Mais donc la question qui me brule les lèvre est "quel est donc ce besoin qui t'incite à faire cohabiter des types à ce point dissemblables "

    Car, si j'ai bien compris, tu devrais aussi envisager d'ajouter le support de std::vector<std::byte>, voir même d'autres collections de std::byte à la liste des types supportés par ton variant

    (*) fais attention au fait que size_t est en réalité un alias de type sur un des type entier non signés (unsigned int, unsigned long ou unsigned long long, selon le système utilisé), et qu'il n'y aura donc -- a priori -- aucune différence entre l'alias de type et le "type original"
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. installation de boost
    Par heinquoi dans le forum Bibliothèques
    Réponses: 2
    Dernier message: 18/04/2005, 17h20
  2. Fichiers, dossier, chemin et lib boost ?
    Par Clad3 dans le forum Bibliothèques
    Réponses: 6
    Dernier message: 24/11/2004, 18h21
  3. Installation de boost (librairie)
    Par dj.motte dans le forum Autres éditeurs
    Réponses: 14
    Dernier message: 21/11/2004, 03h11
  4. boost::serialize
    Par Fry dans le forum Bibliothèques
    Réponses: 6
    Dernier message: 05/11/2004, 18h03
  5. cherchecomment utiliser boost sous linux
    Par Krost dans le forum Autres éditeurs
    Réponses: 1
    Dernier message: 25/02/2004, 22h03

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo