Partage
  • Partager sur Facebook
  • Partager sur Twitter

Connaitre si une variable est une collection

Fonction qui affiche n'importe quel élément ou collection d'éléments

Sujet résolu
    29 avril 2022 à 14:18:48

    Bonjour

    Je voudrais créer une fonction qui affiche n'importe quel élément et collection d'elements. 

    Si c'est un simple type on affiche, sinon (donc si c'est une collection d'éléments) on parcours la liste et on affiche chaque element.

    Mais pour cela je dois connaitre lorsqu'une variable est une collection ou pas, chose que je trouves pas. 

    Vous connaissez comment faire s'il vous plait ?

    -
    Edité par Asmitta 29 avril 2022 à 18:35:14

    • Partager sur Facebook
    • Partager sur Twitter
      29 avril 2022 à 15:15:14

      On peut utiliser du vieux SFINAE pour sélectionner la version de la fonction selon si on lui passe une collection ou pas (en supposant qu'une collection est une classe possédant un begin/end)

      #include <iostream>
      #include <array>
      #include <vector>
      #include <utility>
      #include <type_traits>
      
      template<class, class = void>
      struct IsCollection : std::false_type {};
      
      template<class T>
      struct IsCollection<T,
        std::void_t<decltype(std::begin(std::declval<T>())),
                   decltype(std::end(std::declval<T>()))>> : std::true_type {};
      
      template<class T, std::enable_if_t<!IsCollection<T>::value, int> = 0>
      void print(const T& elem) {
        std::cout << elem << std::endl;
      }
      
      template<class T, std::enable_if_t<IsCollection<T>::value, int> = 0>
      void print(const T& container) {
        std::cout << "( ";
        
        for (const auto& elem : std::as_const(container)) {
          std::cout << elem << ' ';
        }
      
        std::cout << ')' << std::endl;
      }
      
      int main() {
        int a = 3;
        std::array arr{1, 2, 3, 4};
        std::vector vec{"a", "b", "c"};
        
        print(a);
        print(arr);
        print(vec);
      
        // Affiche :
        // 3
        // ( 1 2 3 4 )
        // ( a b c )
      }



      -
      Edité par JadeSalina 29 avril 2022 à 15:16:08

      • Partager sur Facebook
      • Partager sur Twitter
        29 avril 2022 à 15:20:21

        Ou le Design Pattern "Composite", où un élément se comporte comme une liste.
        • Partager sur Facebook
        • Partager sur Twitter
        Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
          29 avril 2022 à 16:02:49

          Merci JadeSalina ta fonction marche bien mais ne fonctionne plus si je tombe sur une collection de collections...

          Je vais essayer de comprendre le code et voir comment le modifier.(edit: en remplacant juste std::cout par print() dans la fonction des collections, la 2nde)

          Je suis tombé sur ceci Composite Design Pattern in C++ (tutorialspoint.com) bacelar, c'est pas très limpide pour moi, pour mon probleme.

          -
          Edité par Asmitta 29 avril 2022 à 16:06:40

          • Partager sur Facebook
          • Partager sur Twitter
            29 avril 2022 à 16:09:29

            Asmitta a écrit:

            Merci JadeSalina ta fonction marche bien mais ne fonctionne plus si je tombe sur une collection de collections...


            Ah oui là on affiche directement l'élément de la collection, il faudrait plutôt appeler à nouveau print, pour repasser récursivement par la fonction qui prend une collection (mais la version normale de print insère un std::endl qu'on ne veut pas forcément, vous voudrez peut être l'enlever pour qu'elle n'affiche que l'élément).

            Après comme vous l'aurez remarqué (je l'espère :o), ma solution est complètement illisible et n'a rien à faire dans du code source destiné à être lu par des humains, ce qui est dommage puisque c'est les humains qui lisent le code source. C++20 améliore un peu les choses à ce niveau là :

            #include <iostream>
            #include <array>
            #include <vector>
            #include <utility>
            #include <ranges>
            
            template<class T>
            concept Collection = std::ranges::range<T>;
            
            template<class T>
            void print(const T& elem) {
              std::cout << elem << std::endl;
            }
            
            void print(const Collection auto& collection) {
              std::cout << "( ";
              
              for (const auto& elem : std::as_const(collection)) {
                std::cout << elem << ' ';
              }
            
              std::cout << ')' << std::endl;
            }
            
            int main() {
              int a = 3;
              std::array arr{1, 2, 3, 4};
              std::vector vec{"a", "b", "c"};
              
              print(a);
              print(arr);
              print(vec);
            }



            -
            Edité par JadeSalina 29 avril 2022 à 16:12:24

            • Partager sur Facebook
            • Partager sur Twitter
              29 avril 2022 à 16:15:52

              >Après comme vous l'aurez remarqué (je l'espère :o), ma solution est complètement illisible et n'a rien à faire dans du code source destiné à être lu par des humains, ce qui est dommage puisque c'est les humains qui lisent le code source

              J'ai rien compris mais Merci, les deux fonctions marchent. Je modifierai selon mes preferences pour l'affichage juste.

              Code: 

              #include <iostream>
              #include <array>
              #include <vector>
              #include <string>
              #include <utility>
              #include <type_traits>
               
              template<class, class = void>
              struct IsCollection : std::false_type {};
               
              template<class T>
              struct IsCollection<T,
                std::void_t<decltype(std::begin(std::declval<T>())),
                           decltype(std::end(std::declval<T>()))>> : std::true_type {};
               
              template<class T, std::enable_if_t<!IsCollection<T>::value, int> = 0>
              void print(const T& elem, int tab) {
                std::cout << elem << " ";
              }
               
              template<class T, std::enable_if_t<IsCollection<T>::value, int> = 0>
              void print(const T& container, int tab = 0) {
                std::cout<<"\n";
                  for (int i = 0; i < tab; i++)
                      std::cout << "\t";
                  std::cout << "{ ";
                 
                for (const auto& elem : container) {
                  print(elem, tab+1);
                  if (elem == container.back())
                      std::cout<<"}\n";
                }
                  for (int i = 0; i < tab-1; i++)
                      std::cout << "\t";
              }
               
              int main() {
                std::vector<std::vector<std::string>> vec{{"a", "b"}, {"c", "d"}};
                vec.push_back({"str", "str2", "str3"});
                vec.push_back({"1", "2", "3", "4"});
                print(vec);
              }

              Affichage: 

              /tmp/JPnuTruNrk.o
              { 
              	{ 
              		{ a }
              	
              		{ b }
              	}
              
              	{ 
              		{ c }
              	
              		{ d }
              	}
              
              	{ 
              		{ s t r }
              	
              		{ s t r 2 }
              	
              		{ s t r 3 }
              	}
              
              	{ 
              		{ 1 }
              	
              		{ 2 }
              	
              		{ 3 }
              	
              		{ 4 }
              	}
              }
              

              -
              Edité par Asmitta 29 avril 2022 à 17:11:14

              • Partager sur Facebook
              • Partager sur Twitter
                29 avril 2022 à 18:51:05

                Dans une approche "Composite", le code client n'a pas à se soucier s'il s'agit d'un élément ou d'une collection. C'est le composite qui sait et c'est bien suffisant.
                • Partager sur Facebook
                • Partager sur Twitter
                Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
                  29 avril 2022 à 19:24:07

                  Je trouves que c'est toujours pas assez précisa.

                  Je vois un composite comme une classe abstraite mère et donc si je suis cette approche faudra ajouter des définitions(l'affichage juste ici) pour chaque type (classe fille) ? Je vais toujours devoir savoir si j'ai affaire a une collection ou un simple type. C'est plus long je trouves, et pas particulièrement necessaire dans mon cas. Enfin je pense

                  • Partager sur Facebook
                  • Partager sur Twitter
                    29 avril 2022 à 19:39:36

                    Si tu n'as besoin que d'un "print", oui, c'est plus long, mais si l'interface de ton composite est plus riche, l'approche composite est bien plus évolutive.

                    On n'a besoin pas besoin de classes supplémentaires, la classe composite sait d'elle-même et sans héritage si c'est une feuille ou une branche. (Cela peut varier en fonction du mode d'implémentation)

                    -
                    Edité par bacelar 29 avril 2022 à 20:06:33

                    • Partager sur Facebook
                    • Partager sur Twitter
                    Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.

                    Connaitre si une variable est une collection

                    × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                    × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                    • Editeur
                    • Markdown