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

C++ Discussion :

appel dynamique de fonction avec ou sans argument


Sujet :

C++

  1. #1
    Futur Membre du Club
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2012
    Messages
    9
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Val d'Oise (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Mai 2012
    Messages : 9
    Points : 8
    Points
    8
    Par défaut appel dynamique de fonction avec ou sans argument
    Bonjour,

    Pour un programme j'ai besoin de créer une classe qui exécute une de ses méthode dans un thread. Cette méthode doit appeler une fonction passé par l'utilisateur à la classe avec un certain temps d'intervalle.

    Pour ceux qui on pas compris, ma classe consiste a pratiquement recrée la classe QTimer que je ne peut pas l'utilisé. La seule chose ou je bloque c'est sur cette appel dynamique d'une fonction qui peut avoir des arguments.

  2. #2
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 189
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 189
    Points : 17 141
    Points
    17 141
    Par défaut
    Les arguments, il faut les wrapper dans l'objet-fonction (appelé aussi foncteur).

    La classe devrait avoir pour membre un std::function<void(void)>, et l'utilisateur n'a qu'a utiliser une lambda, une classe dédiée, bind, ou toute solution similaire, pour créer un Bidule© appelable.
    Mes principes de bases du codeur qui veut pouvoir dormir:
    • Une variable de moins est une source d'erreur en moins.
    • Un pointeur de moins est une montagne d'erreurs en moins.
    • Un copier-coller, ça doit se justifier... Deux, c'est un de trop.
    • jamais signifie "sauf si j'ai passé trois jours à prouver que je peux".
    • La plus sotte des questions est celle qu'on ne pose pas.
    Pour faire des graphes, essayez yEd.
    le ter nel est le titre porté par un de mes personnages de jeu de rôle

  3. #3
    Futur Membre du Club
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2012
    Messages
    9
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Val d'Oise (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Mai 2012
    Messages : 9
    Points : 8
    Points
    8
    Par défaut
    Je veux un fonctionnement plus simple pour l'utilisateur. Du même type que pour thread.

    Par ternel, peut tu donner un exemple s'il te plais

  4. #4
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 115
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 115
    Points : 32 967
    Points
    32 967
    Billets dans le blog
    4
    Par défaut
    std::thread utilise des variadic template pour ça. Rien ne t'empêche de faire ça via std::thread justement.
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  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,
    Citation Envoyé par orilion Voir le message
    Je veux un fonctionnement plus simple pour l'utilisateur. Du même type que pour thread.

    Par ternel, peut tu donner un exemple s'il te plais
    Un foncteur est une structure qui n'expose qu'un seul comportement (hormis celui d'être constructible) : l'opérateur (), qui est utilisé pour l'appel de fonction.

    En simplifiant au maximum, un foncteur aura toujours une tronche proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    struct MonFoncteur{
        TypeDeRetour operator()(/* paramètres éventuels à fournir lors de l'appel */) const;
    };
    et sera toujours utilisé sous une forme proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    int main(){
        MonFoncteur f;
        f(/* arguments nécessaires*//);
    }
    A partir de là, tu peux à peu près tout faire :

    Si la fonction appelante dispose de données qui devront être transmises lors de l'appel, tu peux décider de fournir autant de paramètres que tu veux à ton opérateur (), exactement comme tu le ferais pour n'importe quelle autre fonction, par exemple, sous une forme proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    /* ce foncteur permettra de trier les personnes en fonction de leur nom puis en fonction de leur prénom
    */
    struct LessByNameThenFirstName{
       /* les opérateurs de comparaisons renvoient toujours un booléen */
       bool operator()(Personne const & a, Personne const & b) const{
           return a.nom() < b.nom() ||  // OK pour "Alcazar" et "Dupond"
                  (a.nom() == b.nom() && a.prenom() < b.prenom()) ; // OK pour Durand Albert et Durant Josephine 
       }
    };
    Mais, si, pour une raison ou une autre, la fonction qui devra se charger de faire appel à l'opérateur () devait ne pas disposer des données qui doivent être utilisées comme argument, tu pourrais toujours envisager quelque chose comme
    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
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    /* Le même avec plusieurs fonctions...
     * considérons que celles qui doit effectivement faire appel à l'opérateur() ne connaisse pas les personnes en question
     */
    struct LessByNameThenFirstName{
       LessByNameThenFirstName(Personne const & a, Personne const & b):
           a_{a},b_{b}{}
        Personne /* const & */ a_;
        Personne /* const & */ b_;
        /* les opérateurs de comparaisons renvoient toujours un booléen 
         * Il n'y a plus besoin de fournir les personnes en paramètre, vu qu'on les connait
         * déjà (en tant que données membres
         */
       bool operator()() const{
           return a_.nom() < b_.nom() ||  /* OK pour "Alcazar" et "Dupond"
                     (a_.nom() == b_.nom() && a_.prenom() < b_.prenom()) ; // OK pour Durand Albert et Durant Josephine 
       }
    };
    void foo(LessByNameThenFirstName const & functor){
        /* ... */
       if(functor() ) {
            /*  ... */
       }
    }
    int main(){
        Personne a;
        Personne b;
        /* nous pouvons instancier notre foncteur comme n'importe quel autre structure classique */
        LessByNameThenFirstName functor{a,b};
        /* puis nous pouvons l'utiliser comme n'importe variable, par exemple, en le transmettant à foo
         */
       foo(functor));
       return 0; 
    }
    pour std::bind, le mieux est sans doute encore de suivre la doc... C'est particulièrement long et fastidieux à expliquer

    Les expressions lambda poursuivent le même objectif que les foncteurs, mais avec un écriture simplifiée. Elle prennent généralement la forme de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    [<capture du contexte>](<capture de variable>){
        /* ce qui doit être effectué*/
    }
    Pour reprendre le même exemple, nous pourrions envisager de trier un tableau de personnes à l'aide de la fonction std::sort. Si notre but est de trier ces personnes d'abord par leur nom et ensuite par leur prénom, le code ressemblerait à
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    int main(){
        std::vector<Personne> tab;
        /* il est rempli d'une manière ou d'une autre*/
        std::sort(tab.begin(), 
                  tab.end(), 
                  [/* y a pas de contexte à capturer*/]
                  ( Personne const & a, Personne const & b /* on compare les personnes deux à deux*/){
                      // ce qui doit être fait : on a déjà vu cette logique ;)
                      return a.nom() < b.nom() ||
                            (a.nom() == b.nom() && a.prenom() < b.prenom());
                      });
       /* le tableau est maintenant trié selon nos souhaits */
    }
    L'avantage, c'est que ce genre d'expression lambda peut être utilisé là où on s'attend à recevoir un paramètre de type std::function (tu devrais t'y intéresser )

    PS : oui, tous les liens sont en anglais... j'aurais pu les donner en francais, mais, comme la plupart des ressources concernant le développement sont en anglais, autant t'y habituer rapidement
    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

  6. #6
    Futur Membre du Club
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2012
    Messages
    9
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Val d'Oise (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Mai 2012
    Messages : 9
    Points : 8
    Points
    8
    Par défaut
    La classe utilise thread pour exécuté une méthode run.

    Dans cette méthode run, il y a ce qui faut pou exécute en boucle certaine instruction avec intervalle de temps que l'utilisateur rentre quand il crée la classe.

    Appelé un thread dans un autre juste pour faire sa n'est pas correcte.

    J'ai donc deux problème :
    - comment je stock les "Args...args" de mon template dans ma classe
    - comment j'appel ma fonction avec ses arguments.

    Ps: même dans la littérature anglaise je n'arrive pas a trouvé ces réponses.

  7. #7
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 115
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 115
    Points : 32 967
    Points
    32 967
    Billets dans le blog
    4
    Par défaut
    Pourrait-on avoir enfin un peu de code ?
    Ce que tu demandes à faire est plutôt commun je ne vois pas ce qui te bloques.
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  8. #8
    Membre expert
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2011
    Messages
    739
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2011
    Messages : 739
    Points : 3 627
    Points
    3 627
    Par défaut
    Citation Envoyé par orilion Voir le message
    J'ai donc deux problème :
    - comment je stock les "Args...args" de mon template dans ma classe
    - comment j'appel ma fonction avec ses arguments..
    Les 2 problèmes se solutionnent avec std::function et une lambda.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    template<class F, class... T>
    void foo(F && f, T && ... args) {
      std::function<void()> func([f = std::forward<F>(f), args = std::forward<T>(args)...]{ // c++14. simplement `[=]` si on se fiche du perfect forwarding
        f(args...);
      });
     
      func();
    }

  9. #9
    Futur Membre du Club
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2012
    Messages
    9
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Val d'Oise (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Mai 2012
    Messages : 9
    Points : 8
    Points
    8
    Par défaut
    Dans l'état actuelle il ne compile pas, par contre on enlève le template et je qui va avec, la fonction qu'on met en dure sera exécuté sur un intervalle de temps qu'on veux.

    C'est du c++11

    - timer.h :
    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
    20
    21
    22
    23
    24
    25
    26
    27
     
    #ifndef TIMER_H
    #define TIMER_H
     
    #include <atomic>
    #include <thread>
    #include <chrono>
    #include <iostream>
    #include <list>
     
    using namespace std;
     
    class Timer {
    private:
        std::atomic_bool done_ {};
        thread worker_{};
        chrono::milliseconds time;
        void run_();
        Fn** fn; //Fonction à exécuté
        Args** args; // Argument de la fonction
    public:
       template <class Fn, class... Args>
        Timer(chrono::milliseconds time, Fn&& fn, Args&&... args);
        ~Timer();
    };
     
    #endif // TIMER_H
    - timer.cpp :

    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
    20
    21
    22
    23
    24
    25
    26
     
    #include "timer.h"
     
    template <class Fn, class... Args>
    Timer::Timer(chrono::milliseconds time,Fn&& fn, Args&&... args){
        this->time = time;
        this->fn = fn;
        this->args = args;
        worker_ = thread(&Timer::run_,this);
    }
     
    void Timer::run_(){
        while(!this->done_.load()){
            //fonction a exécuté
            this_thread::sleep_for(time);
        }
    }
     
    Timer::~Timer(){
        done_.store(true);
        if(worker_.joinable())
            worker_.join();
        else
           cout << "thread termined" << endl;
     
    }

  10. #10
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 115
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 115
    Points : 32 967
    Points
    32 967
    Billets dans le blog
    4
    Par défaut
    Un moment donné il faudrait lire et essayer de comprendre ce qu'on te raconte, sinon préviens-nous qu'on perd du temps.
    Il t'a été dit 100 fois d'utiliser une lambda et std::function, et tu nous inventes des syntaxes... sans compter l'écriture d'une implémentation de template dans un cpp... Peut-être que revoir un peu les bases ne ferait pas de mal.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    template< class Fn, class... Args>
    class Toto {
    std::function<void(void)> mFunc;
    public:
     Toto(Fn&& fn, Args&&... args) : mFunc([]() { Fn(args...); }) {}
     void AppelleCaRunSiCaTamuse() { while(!done) { mFunc(); } }
    Si ton utilisateur est assez intelligent pour savoir ce qu'est une lambda et en fournir une lui-même tu peux te contenter de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    class Toto {
    std::function<void(void)> mFunc;
    public:
     Toto(std::function<void(void)> func) : mFunc(func) {}
     void AppelleCaRunSiCaTamuse() { while(!done) { mFunc(); } }
    Ou directement plus proche de ton truc
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    worker_ = thread([this]() { run(); });
    ...
    void Toto::run(std::function<void(void)> func) { ... func(); ... }
    A la louche.
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

Discussions similaires

  1. Réponses: 4
    Dernier message: 09/03/2014, 09h38
  2. Fonction avec et sans arguments
    Par moussecp dans le forum MATLAB
    Réponses: 2
    Dernier message: 09/04/2010, 22h28
  3. appel d'une fonction avec pointeur comme argument
    Par airness86180 dans le forum Débuter
    Réponses: 1
    Dernier message: 06/03/2009, 13h34
  4. [JavaScript] [FAQ] Appeler dynamiquement une fonction et passer une fonction en argument
    Par SpaceFrog dans le forum Contribuez
    Réponses: 0
    Dernier message: 28/05/2008, 14h48
  5. Appel dynamique de fonctions
    Par smyley dans le forum MFC
    Réponses: 4
    Dernier message: 27/10/2005, 12h53

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