Partage
  • Partager sur Facebook
  • Partager sur Twitter

Iterateurs, problème avec un predicate

Sujet résolu
    3 juillet 2019 à 22:11:37

    Bonjour à tous,

    Je reçois une error avec ce morceau de code du cours "Zeste de savoir", à cause semble-t'il du predicate "isspace"

    J'ai pu faire autrement simplement en créant 3 itérateurs remove sur chacun des espaces possibles " " "\t" "\n"

    Cependant, faisant parti du cours, & étant plus court en terme de code, j'aimerai comprendre ce qui ne va pas.. (j'ai essayé sous windows avec Code::Blocs + sous Linux avec g++)

    #include <iostream>
    #include <string>
    #include <algorithm>
    #include <cctype>
    
    using namespace std;
    
    int main()
    {
    std::string test { "\n\tHello !\n\t" };
        std::cout << "Avant modification : " << test << std::endl;
    
        // On utilise l'itérateur fourni par std::find_if_not, qui pointe sur le premier élément qui n'est pas un espace.
        auto premier_non_espace { std::find_if_not(std::begin(test), std::end(test), isspace) };
        test.erase(std::begin(test), premier_non_espace);
        // On affiche pour tester.
        std::cout << "Suppression au début : " << test << std::endl;
    
        return 0;
    }

    Et voici le message d'erreur que je reçois :

    error: no matching function for call to 'find_if_not(std::__cxx11::basic_string<char>::iterator, std::__cxx11::basic_string<char>::iterator, <unresolved overloaded function type>)'|
    
    note:   couldn't deduce template parameter '_Predicate'|


    Merci (:

    -
    Edité par Nektar_ia 3 juillet 2019 à 22:12:12

    • Partager sur Facebook
    • Partager sur Twitter
      3 juillet 2019 à 22:40:28

      En réalité, il existe 2 versions de isspace: une dans <cctype> et une autre dans <locale> inclut par <iostream>. Malheureusement, lorsque tu passes isspace en paramètre, le compilateur ne sait pas laquelle prendre. Il existe 2 manière de contourner le problème:

      • un cast vers la bonne signature. Puisque les 2 fonctions ont une signature différente, le compilateur choisira celle qui correspond.
      • faire l'appel dans une lambda/une autre fonction. Le compilateur déduira la bonne fonction selon le nombre et les types des paramètres.
      auto premier_non_espace { std::find_if_not(std::begin(test), std::end(test), [](char c) {
        return std::isspace(c);
      }) };

      Au besoin, tu peux passer par une variable intermédiaire:

      auto predicate = [](char c) { return std::isspace(c); };
      auto premier_non_espace { std::find_if_not(std::begin(test), std::end(test), predicate) };

      -
      Edité par jo_link_noir 3 juillet 2019 à 22:41:07

      • Partager sur Facebook
      • Partager sur Twitter
        4 juillet 2019 à 2:57:31

        Merci pour ta réponse

        Ca fonctionne bien, j'ai mis le sujet en résolu (:

        Je suis encore un peu court pour comprendre 100% de ce que tu as écris.. spécialement cette syntaxe :

        [](char c)

        Si tu as un moment pour aussi me montrer un exemple de "cast vers la bonne signature" (j'ai vu en effet qu'il y avait 2 versions de la fonction, une qui retourne un bool (& prend 2 paramètres, un charT c + const locale &__loc), une qui retourne un int (& prend un int paramètre)..peut-être parce que cette dernière vient du C )

        Thx again (:

        • Partager sur Facebook
        • Partager sur Twitter
          4 juillet 2019 à 3:19:26

          > Si tu as un moment pour aussi me montrer un exemple de "cast vers la bonne signature"

          static_cast<int(*)(int)>(isspace)

          Le [](char c) { ... } est une lambda, tu peux voir cela comme une fonction créée sur place qui prend ici un paramètre 'c'. Pour plus de détail, il y a cppreference (https://en.cppreference.com/w/cpp/language/lambda), mais tu le verras probablement un peu plus tard.

          -
          Edité par jo_link_noir 4 juillet 2019 à 3:21:05

          • Partager sur Facebook
          • Partager sur Twitter
            4 juillet 2019 à 9:09:59

            N'oubliez pas de caster le char en unsigned char pour l'argument de isspace. En effet peu de gens font attention mais c'est UB si la valeur du caractère n'est pas égale à EOF ou représentable par unsigned char.

            https://en.cppreference.com/w/cpp/string/byte/isspace

            Edit : typo (merci jo_link_noir)

            -
            Edité par markand 5 juillet 2019 à 8:51:53

            • Partager sur Facebook
            • Partager sur Twitter

            git is great because Linus did it, mercurial is better because he didn't.

            Anonyme
              4 juillet 2019 à 9:17:22

              Salut Nektar_ia.

              Bizarre, je viens de tester avec GCC 9 en compilant comme ceci : g++ --std=c++17 main.cpp -o main.out, en reprenant le même code que toi, et je n'ai aucune erreur, pas plus qu'avec Visual Studio 2017 / 2019.

              Tu as bien compilé en C++17 ?

              • Partager sur Facebook
              • Partager sur Twitter
                4 juillet 2019 à 17:48:47

                > N'oubliez pas de caster le char en unsigned int pour l'argument de isspace.

                unsigned char*

                @GlovedWoman: Sur godbolt, gcc et clang se vautrent: https://godbolt.org/z/6LCdJi

                • Partager sur Facebook
                • Partager sur Twitter
                  5 juillet 2019 à 1:20:42

                  Merci à tous pour vos précisions

                  GlovedWoman a écrit:

                  Salut Nektar_ia.

                  Bizarre, je viens de tester avec GCC 9 en compilant comme ceci : g++ --std=c++17 main.cpp -o main.out, en reprenant le même code que toi, et je n'ai aucune erreur, pas plus qu'avec Visual Studio 2017 / 2019.

                  Tu as bien compilé en C++17 ?

                  Je viens de tester, & en effet, le seul endroit ou cela passe pour moi (je ne me sers pas de VS2019, la license va bientôt expirer, & il y a beaucoup trop d'options inutiles à mon niveau d'apprentissage &.. croyez-le ou non, c'est de loin le plus long (comparé à code::blocks & g++) à compiler & lancer la console pour tester le programme. Mais tu as raison, en l'état sous VS2019, ça passe. Par contre, g++ sous Linux, même en --std=c++17 c'est non (j'ai vérifié, version 7.4 pour mon g++.. je tiens mon Linux à jour, je ne comprends pas trop pourquoi je n'ai pas, ne serais-ce que la 8..)

                  Ps: Très intéréssant Godbolt, merci pour le trick

                  -
                  Edité par Nektar_ia 5 juillet 2019 à 1:24:14

                  • Partager sur Facebook
                  • Partager sur Twitter
                    5 juillet 2019 à 2:28:03

                    Pour avoir une version récente de gcc, il faut soit une distribution récente (souvent la version majeure de gcc et unique à la version de la distribution), soit recompiler à la main. C'est assez facile, il suffit de lancer un script dans le dossier contrib des sources de gcc, puis utiliser la procédure d'installation classique quelque dans le README ou sur le site. Et attendre quelques heures...

                    Sinon, certaines distributions ont un paquet gcc-snapshot, pas de dernière version, mais un peu plus récent. Mais le binaire s'installe je ne sais plus où, du coup il n'est pas dans le PATH par défaut.

                    • Partager sur Facebook
                    • Partager sur Twitter

                    Iterateurs, problème avec un predicate

                    × 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