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 :

Tableau d'appels de fonction / lambda / templates


Sujet :

C++

  1. #1
    Membre émérite
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    2 764
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 2 764
    Points : 2 705
    Points
    2 705
    Par défaut Tableau d'appels de fonction / lambda / templates
    Bonjour,

    J'aimerais appeler en parallèle (multithreading) une série d'instanciation d'une fonction libre template dont la signature est (pour simplifier) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    template <typename T>
    int maFonction(std::string param1, T param2);
    J'aimerais, pour lancer mes threads, utiliser une boucle, comme décrit sur cette page.

    Je dois donc faire un tableau d'"appels de fonction". Tous les arguments de la fonction, pour chaque instanciation, sont connus à la construction du tableau. Je pense doncqu'il faut créer un tableau de std::function (mais bon... je maîtrise mal ces sujets).

    M'orienté-je sur une bonne piste ?

  2. #2
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    Tu ne pourras pas créer un tableau sur fonctions de paramètres de types différents, par contre. Pour ça, il faudra de la virtualité en plus des templates.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  3. #3
    Membre émérite
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    2 764
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 2 764
    Points : 2 705
    Points
    2 705
    Par défaut
    Citation Envoyé par Médinoc Voir le message
    Tu ne pourras pas créer un tableau sur fonctions de paramètres de types différents, par contre.
    Je n'arrive même pas à faire ça :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    std::function<int(std::string, float)> monWrapper= maFonction<float>("une_chaine", 0.5);
    Je ne comprend pas ce qui défrise le compilateur.

    Citation Envoyé par Médinoc Voir le message
    Pour ça, il faudra de la virtualité en plus des templates.
    Je tiens à garder mes fonctions libres.
    No way, a priori.

  4. #4
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    Je viens de regarder parce que je ne connais pas std::function et Cie, et il semblerait que std::function ne mémorise qu'un pointeur de fonction, sans paramètres.

    Regarde plutôt du côté de std::mem_fn qui semble mémoriser des paramètres en plus.Edit: Ben non plus, en fait.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  5. #5
    Membre émérite
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    2 764
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 2 764
    Points : 2 705
    Points
    2 705
    Par défaut
    Citation Envoyé par Médinoc Voir le message
    Je viens de regarder parce que je ne connais pas std::function et Cie, et il semblerait que std::function ne mémorise qu'un pointeur de fonction, sans paramètres.
    Si. Regarde sur CPP Reference, le deuxième exemple (store a lambda).

  6. #6
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    Personnellement, je verrais un truc du genre:
    Code C++ : 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
    34
    35
    36
    37
    class FunctionCallerBase
    {
    public:
    	virtual ~FunctionCallerBase();
    	virtual void call() = 0;
     
    };
    //Fonction statique facile à utiliser dans diverses APIs de multithreading
    //Changer les types (void*, convention d'appel, etc.) au besoin.
    void Call(FunctionCallerBase *p)
    {
    	p->call();
    }
     
    template< class T >
    class MaFonction_Caller : FunctionCallerBase
    {
    	int (*m_pFonc)(std::string, T);
    	std::string m_arg1;
    	T m_arg2;
    public:
    	int ret;
    public:
    	MaFonction_Caller(int (*pFonc)(std::string, T), std::string arg1, T arg2)
    	 : m_pFonc(pFonc), m_arg1(arg1), m_arg2(arg2) { }
     
    	void call()
    	{
    		ret = m_pFonc(m_arg1, m_arg2);
    	}
    };
     
    template<class T>
    FunctionCallerBase* WrapMaFonction(std::string arg1, T arg2)
    {
    	return new MaFonction_Caller<T>(MaFonction<T>, arg1, arg2);
    }
    Et ça s'utiliserait ainsi:
    Code C++ : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    FunctionCallerBase* fonctions[] = { 
    	WrapMaFonction("une_chaine", 0.5),
    	WrapMaFonction("une_chaine", 42),
    	WrapMaFonction("une_chaine", "toto")
    };
     
    ...
     
    for( i=0 ; i<ARRAYSIZE(functions) ; ++i )
    	whatever_create_thread(Call, fonctions[i]);
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  7. #7
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    Citation Envoyé par oodini Voir le message
    Si. Regarde sur CPP Reference, le deuxième exemple (store a lambda).
    Ah, dans ce cas, ça s'utiliserait plutôt comme ça:
    Code C++11 : Sélectionner tout - Visualiser dans une fenêtre à part
    std::function<int()> monWrapper= []() { return maFonction<float>("une_chaine", 0.5); }
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  8. #8
    Membre émérite
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    2 764
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 2 764
    Points : 2 705
    Points
    2 705
    Par défaut
    On avance : j'ai réussi à faire ça :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    std::function<float()> test = []() -> float { return std::max(2.2, 5.7); };

  9. #9
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    Ce qui dans notre cas, donnerait:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    std::function<int()> monWrapper= []() -> int { return maFonction<float>("une_chaine", 0.5); }
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  10. #10
    Membre émérite
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    2 764
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 2 764
    Points : 2 705
    Points
    2 705
    Par défaut
    C'est là que ça se complique :
    la fonction et un des arguments sont des membres de la classe créant le wrapper.

    En gros, j'ai :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    class A
    {
        std::string attribut1;
        std::string attribut2;
        template <typename T>
        int maFonction(std::string param1, T param2);
     
        void fonction_d_appel()
        {
            maFonction(attribut1, 0.5);
            maFonction(attribut2, 0.7);
        }
    }
    C'est là que je m'aperçois que ma fonction n'est pas du tout libre (problème d'indentation). Et qu'elle n'est pas publique. Désolé !
    Je pense donc que ça exclut les lambdas.

    Disons que j'ai 10 attributs, et 10 appels de fonction que je veux paralléliser.

  11. #11
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    Je ne pense pas que ça change grand-chose pour les lambdas.
    Si tu n'es pas sûr, copie-les dans des variables locales d'abord.
    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
    class A
    {
        std::string attribut1;
        std::string attribut2;
        template <typename T>
        int maFonction(std::string param1, T param2);
     
        void fonction_d_appel()
        {
            std::string attr1 = attribut1;
            std::string attr2 = attribut2;
     
            std::function<int()> monWrapper[10]; //Mettre ça sur le tas si nécessaire
            monWrapper[0] = []() -> int { return maFonction<float>(attr1, 0.5); };
            monWrapper[1] = []() -> int { return maFonction<float>(attr2, 0.7); };
        }
    }
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  12. #12
    Membre émérite
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    2 764
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 2 764
    Points : 2 705
    Points
    2 705
    Par défaut
    En fait, pour pouvoir se référer à des membres, il faut capturer this dans l'expression lambda.

  13. #13
    Membre émérite
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    2 764
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 2 764
    Points : 2 705
    Points
    2 705
    Par défaut
    Si je suis ta suggestion (voir plus haut), et que je rajoute this :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    std::function<int()> monWrapper= [this]() -> int { return maFonction<float>("une_chaine", 0.5); }
    Le compilateur me sort :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    error C2062: type 'float' unexpected
    Cela ne fonctionne pas non plus avec auto :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    auto monWrapper= [this]() -> int { return maFonction<float>("une_chaine", 0.5); }
    Il faut sûrement déclarer la nature template au début de l'instruction. Je cherche...

    PS : fil de discussion à déplacer dans la section langage, je pense...

  14. #14
    Membre émérite
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    2 764
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 2 764
    Points : 2 705
    Points
    2 705
    Par défaut
    Enfer et damnation ! C'est un bug de VS 2010 !

    http://connect.microsoft.com/VisualS...details/718297

    Il faut donc faire :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    std::function<int()> monWrapper= [this]() -> int { return this->maFonction<float>("une_chaine", 0.5); }

  15. #15
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    Attends, je croyais que c'était supposé être une fonction libre?
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  16. #16
    Membre émérite
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    2 764
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 2 764
    Points : 2 705
    Points
    2 705
    Par défaut
    Mon message d'hier à 18h24 indiquait que finalement, non...

  17. #17
    Membre émérite
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    2 764
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 2 764
    Points : 2 705
    Points
    2 705
    Par défaut
    Bon, j'ai conjugué tout ça avec un vecteur de threads, et j'ai réussi à faire ce que je voulais.

    Merci de t'être penché sur mon problème, Médinoc !

  18. #18
    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,

    Le problème, c'est que, que tu travailles avec un pointeur de fonction "classique" ( void (funptr *)(/* parametres*/ ) ) ou avec un std::function, la signature correspond à l'ensemble de la signature de la fonction (le type de retour, le type éventuel de l'objet au départ duquel tu veux appeler la fonction et le nombre et le type des paramètres à transmettre).

    Si tu veux pouvoir faire varier l'une ou l'autre de ces parties, il faut que tu trouves le "plus grand élément commun" et que tu bindes le reste pour que cela fonctionne.

    Si tu as deux fonctions, mettons
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    void foo( int);
    void bar(float);
    tu pourras créer une collection de std:function (pointeurs sur fonction) sur void (*)(), mais tu devra "binder" le int ou le float.

    Et pour pouvoir l'utiliser sur une fonction membre, il faudra que tu binde également l'objet au départ duquel la fonction est appelée ( this, pour faire simple).

    A moins bien sur que tu crées une collection de fonctions prenant un int ( void (*)(int) ) en paramètre d'un coté et une collection de fonctions prenant un float ( void (*) (float) ) de l'autre coté, et ainsi de suite

    Ceci dit, je me souviens avoir abordé ce point il y a quelques mois en voyant comment il serait possible d'outiller des fonctions afin de savoir leurs temps d'exécutions...

    Je ne sais plus de tête quelle était la discussion, mais tu devrais pouvoir la retrouver "assez facilement" (bon, mon utilisation ne s'intéressait pas aux lambda, mais tu devrais pouvoir adapter l'idée "assez facilement" )

    PS : je le sais, ma bonté me perdra, mais j'ai même retrouvé l'intervention dont je te parlais... elle se trouve ici
    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

  19. #19
    Membre émérite
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    2 764
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 2 764
    Points : 2 705
    Points
    2 705
    Par défaut
    Citation Envoyé par koala01 Voir le message
    Si tu veux pouvoir faire varier l'une ou l'autre de ces parties, il faut que tu trouves le "plus grand élément commun" et que tu bindes le reste pour que cela fonctionne.
    Oui, c'est ce que j'ai fait.

    Citation Envoyé par koala01 Voir le message
    Ceci dit, je me souviens avoir abordé ce point il y a quelques mois en voyant comment il serait possible d'outiller des fonctions afin de savoir leurs temps d'exécutions...
    Comme j'ai réussi à faire ce que je voulais, je ne vais pas lire ta prose pour résoudre mon problème (qui n'en est plus un), mais ça reste un post très intéressant que je prendrai le temps de lire !

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

Discussions similaires

  1. label, tableau et appel de fonction dans une boucle
    Par amine2208 dans le forum Général JavaScript
    Réponses: 10
    Dernier message: 29/04/2013, 15h02
  2. Appeler une fonction avec un tableau en parametre ?
    Par devoluti0n dans le forum C++
    Réponses: 9
    Dernier message: 11/04/2008, 16h21
  3. Aide tableau appels de fonction
    Par pepsi33 dans le forum C++
    Réponses: 2
    Dernier message: 08/11/2007, 08h20
  4. Réponses: 1
    Dernier message: 25/07/2007, 10h03
  5. Réponses: 4
    Dernier message: 21/04/2007, 20h02

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