Partage
  • Partager sur Facebook
  • Partager sur Twitter

Fold Expression

Sujet résolu
    24 octobre 2018 à 17:07:35

    Bien le Bonjour,

    J'avais le nez dans la doc quand je suis tombé par hasard sur les Fold Expression. Au premier abord, ce fût comme une rencontre avec un extra-terrestre, puis j'ai essayé de comprendre ce machin.

    Donc d'après ce que j'ai pu comprendre pour le moment, ce serait du sucre syntaxique évitant du code superflu lors de l'utilisation de paramater pack permettant de se passer d'une surcharge de la fonction de traitement pour stopper la récursion ?

    Du coup pour m'entraîner un peu, j'ai repris un bout de code que @koala m'avait sympatiquement fourni il y a quelques mois (FootprintCreator : trouvable ici) et j'ai donc essayé de le remodeler sous forme de fold expression ce qui donne :

    #include <iostream>
    #include <bitset>
    #include <map>
    #include <typeinfo>
    #include <typeindex>
    
    ///////////////////////////////////////////////////////////////////////
    struct Position
    {
        float x{};
        float y{};
    };
    
    struct Velocity
    {
        float x{};
        float y{};
    };
    
    std::map<const std::type_index, const size_t> mapper{
        {std::type_index(typeid(Position)), 0},
        {std::type_index(typeid(Velocity)), 1}
    };
    
    ///////////////////////////////////////////////////////////////////////
    template<typename... Args>
    struct FootprintCreator
    {
        static std::bitset<64> create(){
            std::bitset<64> key{};
            return (key.set(mapper[typeid(Args)]) | ...);
        }
    };
    
    ///////////////////////////////////////////////////////////////////////
    int main()
    {
        std::bitset<64> key = FootprintCreator<Position, Velocity>::create();
        std::cout << key.to_string() << '\n';
    
        return 0;
    }

    (Avoue que tu es impressionné @koala :lol:)

    Donc pour le moment j'ai fait quelques tests et pas de souci particulier. Mais est-ce que c'est quelque chose que l'on peut utiliser systématiquement sans problème lorsque l'on a affaire a du paramater pack ? Ou il y a certaines limites à prendre en compte ?

    Merci.

    -
    Edité par Guit0Xx 24 octobre 2018 à 17:20:18

    • Partager sur Facebook
    • Partager sur Twitter

    ...

      24 octobre 2018 à 17:20:31

      Je n'ai pas le souvenir d'avoir vu des limitations spécifiques avec les folding expressions.

      (On est en train de préparer un article sur le C++17 sur ZdS. Je ferais probablement une review plus poussées des folds a ce moment là, mais rien pour le moment)

      • Partager sur Facebook
      • Partager sur Twitter
        24 octobre 2018 à 17:26:23

        gbdivers a écrit:

        Je n'ai pas le souvenir d'avoir vu des limitations spécifiques avec les folding expressions.

        D'acc.

        gbdivers a écrit:

        (On est en train de préparer un article sur le C++17 sur ZdS. Je ferais probablement une review plus poussées des folds a ce moment là, mais rien pour le moment)

        Ça marche merci pour l'info.

        • Partager sur Facebook
        • Partager sur Twitter

        ...

          24 octobre 2018 à 20:11:33

          Avant les folds il y a possibilité de déballer l'expression dans un tableau puis de l'ignorer. Si on veut faire une opération binaire comme le | de ton exemple, il fallait utiliser une variable intermédiaire. (voir mon article).

          Par contre, les folds ne permettent pas d'arrêter un parcours. On travaille sur toutes les valeurs ou aucune. La seule chose qui s'apparente à un arrêt dans le parcours sont les opérateurs logiques && et ||. Ces opérateurs sont paresseux, càd que dans a || b, si a est vrai alors b n'est jamais exécuté. Avec les folds c'est pareil, mais l'écriture est plus tordue quand on veut réécrire une fonction récursive qui contient des if/else. Si on ne veut pas passer par une fonction intermédiaire, je n'ai pas trouvé mieux qu'une lambda qui retourne un booléen.

          ([]{
            if (xs.foo()) {
              // des trucs
              return true;
            }
            // encore des trucs
            return false;
          }() || ...);
          

          -
          Edité par jo_link_noir 24 octobre 2018 à 20:12:53

          • Partager sur Facebook
          • Partager sur Twitter
            24 octobre 2018 à 22:47:00

            jo_link_noir a écrit:

            Avant les folds il y a possibilité de déballer l'expression dans un tableau puis de l'ignorer. Si on veut faire une opération binaire comme le | de ton exemple, il fallait utiliser une variable intermédiaire. (voir mon article).

            Oula j'ai sursauté en voyant la macro, quelle bête étrange ^^.

            jo_link_noir a écrit:

            Par contre, les folds ne permettent pas d'arrêter un parcours. On travaille sur toutes les valeurs ou aucune.

            Ah yes d'accord.

            jo_link_noir a écrit:

            Avec les folds c'est pareil, mais l'écriture est plus tordue quand on veut réécrire une fonction récursive qui contient des if/else. Si on ne veut pas passer par une fonction intermédiaire, je n'ai pas trouvé mieux qu'une lambda qui retourne un booléen.

            Avec les opérateurs && et || ? Pour le coup je ne suis pas sûr de comprendre, tu aurais un petit exemple sans lambda avec une fonction intermédiaire ?

            • Partager sur Facebook
            • Partager sur Twitter

            ...

              24 octobre 2018 à 23:55:41

              Un truc souvent effectué avec un pointeur est par exemple de vérifier qu'il est valide pour appeler une fonction membre. Par exemple "if (p && p->check())". La seconde partie (i.e. "p->check()") ne sera pas exécuté si p est nul.

              Avec un fold c'est pareil. Si j'ai un pack d'objet qui possède chacun une fonction advance() qui retourne un booléen, je peux faire "(xs.advance() && ... )" et dès qu'il y a un false en retour, le fold s'arrête.

              struct A
              {
                bool advance()
                {
                  if (i > 2) {
                    return false;
                  }
                  ++i;
                  return true;
                }
              
                int i = 0;
              };
              
              template<class... Ts>
              void foo(Ts& ...xs)
              {
                (xs.advance() && ...);
              }
              
              #include <iostream>
              
              int main()
              {
                A a;
                foo(a,a,a,a,a,a,a,a,a,a,a); // très pertinent
                std::cout << a.i; // affiche 3
              }

              -
              Edité par jo_link_noir 25 octobre 2018 à 15:45:16

              • Partager sur Facebook
              • Partager sur Twitter
                25 octobre 2018 à 15:39:01

                Ah je vois ok ! Merci bien.

                -
                Edité par Guit0Xx 25 octobre 2018 à 15:40:16

                • Partager sur Facebook
                • Partager sur Twitter

                ...

                Fold Expression

                × 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