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

Boost C++ Discussion :

[Boost.Function] Appeler une fonction "externe"


Sujet :

Boost C++

  1. #1
    Membre chevronné
    Avatar de poukill
    Profil pro
    Inscrit en
    Février 2006
    Messages
    2 155
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France

    Informations forums :
    Inscription : Février 2006
    Messages : 2 155
    Points : 2 107
    Points
    2 107
    Par défaut [Boost.Function] Appeler une fonction "externe"
    Salut à tous,

    Dans le cadre d'un travail en équipe, j'aimerais me servir d'une fonction membre utilisé par mon collègue, dont je n'ai pas besoin de connaitre le code source normalement.

    Voici ma fonction que j'aimerai créer (l'utilisation de Boost.Fonction est très certainement mauvaise):

    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
    void Camera::creerFilm(boost::function<void (vigra::UInt16Image & )> & fonct, int image_debut, int image_fin, std::string nom_fichier)
    {
    	std::cout << "Generation d'un film en cours..." << std::endl;
    	std::ofstream file ( nom_fichier.c_str(), std::ios_base::binary);
    
    	for (int i = image_debut; i < image_fin; i++) {
    		if (isNumeroValide(i) ) {
    			vigra::UInt16Image image = getImage(i);
                            fonc(image); // Traitement à appliquer ICI
    			
    		
    			vigra::UInt16Image::const_iterator iter;
    			for (iter = image.begin(); iter != image.end(); iter++) {
    				file.write(reinterpret_cast<const char*>(iter), sizeof(vigra::UInt16));
    			}
    		}
    	}
    }
    J'aimerai recevoir un pointeur de fonction de sa part, fonction dont je ne connais pas a priori l'implémentation:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    void applyTreatment(vigra::UInt16Image & image)
    {
       //Code
    }
    Comment bien utiliser Boost.Function? J'ai beau lire et relire la doc de Boost, je ne vois pas comment m'en servir ? C'est lui qui choisi la fonction à appliquer, et c'est moi qui possède l'argument (image).

    Comment faire?

    Merci de votre aide (encore une fois ! )

  2. #2
    Membre chevronné
    Avatar de poukill
    Profil pro
    Inscrit en
    Février 2006
    Messages
    2 155
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France

    Informations forums :
    Inscription : Février 2006
    Messages : 2 155
    Points : 2 107
    Points
    2 107
    Par défaut
    J'ai avancer un peu sur mon problème maintenant, j'ai un problème d'édition des liens que je n'arrive vraiment pas à résoudre:

    Camera.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
     
    class Foo;
     
    template <typename T>
    void Camera::creerFilm(boost::function<void (T*, vigra::UInt16Image & )> fonct, int image_debut, int image_fin, std::string nom_fichier)
    {
    	std::cout << "Generation d'un film en cours..." << std::endl;
    	std::ofstream file ( nom_fichier.c_str(), std::ios_base::binary);
     
    }
     
    template <typename T>
    void Camera::genererFilm(boost::function<void (T*, vigra::UInt16Image & )> fonct, int image_debut, int image_fin, std::string nom_fichier)
    {
    	boost::thread my_thread(boost::bind(&Camera::creerFilm, this,  fonct, image_debut, image_fin, nom_fichier));	
    }
    main.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
     
    class Foo
    {
    public:
    	Foo() {};
    	void applyTreatment( vigra::UInt16Image & image) { image.init(0);};
    };
     
     
    int	main()
    {
    	Choc choc(37984);
    	Camera_IR cam(choc, "Prisme");
     
    	Foo foo;
    	boost::function<void (Foo*, vigra::UInt16Image & )> f;
    	f = &Foo::applyTreatment;
     
     
    	cam.genererFilm(f, 0, 40, "test");
    }
    main.obj : error LNK2001: symbole externe non résolu "public: void __thiscall Camera::genererFilm<class Foo>(class boost::function<void __cdecl(class Foo *,class vigra::BasicImage<unsigned short,class std::allocator<unsigned short> > &),class std::allocator<void> >,int,int,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >)" (??$genererFilm@VFoo@@@Camera@@QAEXV?$function@$$A6AXPAVFoo@@AAV?$BasicImage@GV?$allocator@G@std@@@vigra@@@ZV?$allocator@X@std@@@boost@@HHV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z)

  3. #3
    Rédacteur
    Avatar de Laurent Gomila
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    10 651
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 10 651
    Points : 15 920
    Points
    15 920
    Par défaut
    http://cpp.developpez.com/faq/cpp/?p...VERS_templates

    Et je pense que tu cherches beaucoup trop compliqué avec boost.function. Il te suffit de déclarer le prototype que tu souhaites manipuler (un truc qui prend un UInt16Image& et ne renvoie rien), et de lui faire correspondre ce que tu as à passer en paramètre avec boost.bind, peu importe que ce soit une fonction membre ou une fonction qui prend plus de paramètres.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    void Camera::genererFilm(boost::function<void (vigra::UInt16Image & )>, ...);
     
    cam.genererFilm(boost::bind(&Foo::applyTreatment, foo),...);

  4. #4
    Membre chevronné
    Avatar de poukill
    Profil pro
    Inscrit en
    Février 2006
    Messages
    2 155
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France

    Informations forums :
    Inscription : Février 2006
    Messages : 2 155
    Points : 2 107
    Points
    2 107
    Par défaut
    Citation Envoyé par Boost Doc
    In many systems, callbacks often call to member functions of a particular object. This is often referred to as "argument binding", and is beyond the scope of Boost.Function. The use of member functions directly, however, is supported, so the following code is valid:
    Pourtant, c'est clairement indiqué dans la doc qu'il y a une différence!
    http://www.boost.org/doc/html/function/tutorial.html

    Dans le cas d'une structure X:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    struct X {
      int foo(int);
    };
    On devrait écrire avec une fonction membre:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    boost::function<int (X*, int)> f;
     
    f = &X::foo;
     
    X x;

  5. #5
    Membre expérimenté

    Profil pro
    Inscrit en
    Juin 2006
    Messages
    1 294
    Détails du profil
    Informations personnelles :
    Localisation : Royaume-Uni

    Informations forums :
    Inscription : Juin 2006
    Messages : 1 294
    Points : 1 543
    Points
    1 543
    Par défaut
    Salut,

    Souvent dans ces cas-là j'hésite pas et je fais un truc du genre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    template< typename F >
    void Camera::creerFilm(F fonct, int image_debut, int image_fin, std::string nom_fichier)
    {
      // ...
      fonc(image);
    }
    Et tout se passe bien tant qu'on donne un foncteur qui prend en argument le bon type.

    Sinon avec boost::function il faut faire quelque chose comme :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    void Camera::creerFilm( boost::function1< void, vigra::UInt16Image& > fonct, int image_debut, int image_fin, std::string nom_fichier)
    {
      // ...
      fonc(image);
    }
    Et pour l'appel :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    Foo foo;
    camera.creerFilm( boost::bind( &Foo::applyTreatment, foo, _1 ) );
    (si je ne me suis pas trop mélangé les pinceaux )
    (edit : ah ben si j'avais oublié 'foo' !)

    MAT.

  6. #6
    Membre éclairé Avatar de HanLee
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    738
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France, Rhône (Rhône Alpes)

    Informations forums :
    Inscription : Mai 2004
    Messages : 738
    Points : 871
    Points
    871
    Par défaut
    Citation Envoyé par poukill Voir le message
    Pourtant, c'est clairement indiqué dans la doc qu'il y a une différence!
    http://www.boost.org/doc/html/function/tutorial.html

    Dans le cas d'une structure X:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    struct X {
      int foo(int);
    };
    On devrait écrire avec une fonction membre:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    boost::function<int (X*, int)> f;
     
    f = &X::foo;
     
    X x;
    Ca c'est dans le cas où tu veux appeler cette fonction en fonction de l'objet et des arguments.

    Une fonction membre (pas statique) de n paramètres est en fait toujours une fonction de (n+1) paramètres, car il y a le pointeur this.

    Toi tu ne veux appeler que la fonction membre, tu t'en fous de l'objet vers qui il est appelé.

    Pour cela, il faut faire une application partielle de fonction, c'est à dire créer la même fonction en fixant un ou plusieurs paramètres, c'est ce qu'on fait avec boost::bind.

    Après, les _1, _2, _3 c'est une manière de faire des fonctions lambda en quelque sorte :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    boost::bind(&fonction, a, _1, _2, c);
    équivaut à dire :

    soit la fonction qui à (x,y) associe fonction(a, x, y, c).

  7. #7
    Membre chevronné
    Avatar de poukill
    Profil pro
    Inscrit en
    Février 2006
    Messages
    2 155
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France

    Informations forums :
    Inscription : Février 2006
    Messages : 2 155
    Points : 2 107
    Points
    2 107
    Par défaut
    J'ai modifié mon code, j'ai maintenant:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    void Camera::genererFilm(boost::function<void (vigra::UInt16Image & )> fonct, int image_debut, int image_fin, std::string nom_fichier)
    {
    	boost::thread my_thread(boost::bind(&Camera::creerFilm, this,  fonct, image_debut, image_fin, nom_fichier));	
    }
    Dans le main:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    int	main()
    {
    	Choc choc(37984);
    	Camera cam(choc, "Prisme");
    	Foo foo;
     
    	cam.genererFilm(boost::bind(&Foo::applyTreatment, foo), 0, 40, "test");
    }
    Ca veut pas compiler... Avec un genre d'erreur que j'ai jamais vu (cf pièce jointe)

    Comme warning :
    c:\librairies\boost_1_34_1\boost\bind.hpp(1575) : warning C4180: qualificateur appliqué au type fonction n'a pas de sens ; ignoré
    c:\librairies\boost_1_34_1\boost\bind.hpp(1609) : voir la référence à l'instanciation de la classe modèle 'boost::_bi::add_cref<Pm,I>' en cours de compilation
    with
    [
    Pm=void (__thiscall Foo::* )(vigra::UInt16Image &),
    I=1
    ]
    c:\documents and settings\gwen\bureau\prog\test\main.cpp(32) : voir la référence à l'instanciation de la classe modèle 'boost::_bi::dm_result<Pm,A1>' en cours de compilation
    with
    [
    Pm=void (__thiscall Foo::* )(vigra::UInt16Image &),
    A1=Foo
    ]
    c:\librairies\boost_1_34_1\boost\mem_fn.hpp(318) : warning C4180: qualificateur appliqué au type fonction n'a pas de sens ; ignoré
    c:\librairies\boost_1_34_1\boost\bind\bind_template.hpp(225) : voir la référence à l'instanciation de la classe modèle 'boost::_mfi::dm<R,T>' en cours de compilation
    with
    [
    R=void (vigra::UInt16Image &),
    T=Foo
    ]
    Projet : error PRJ0002 : Résultat d'erreur 1 retourné à partir de 'C:\Program Files\Microsoft Visual Studio 8\VC\bin\cl.exe'.
    Le journal de génération a été enregistré à l'emplacement "file://c:\Documents and Settings\Gwen\Bureau\prog\test\Debug\BuildLog.htm"
    test - 1 erreur(s), 2 avertissement(s)
    Là j'y comprend rien... Une idée?
    Images attachées Images attachées  

  8. #8
    Membre expérimenté

    Profil pro
    Inscrit en
    Juin 2006
    Messages
    1 294
    Détails du profil
    Informations personnelles :
    Localisation : Royaume-Uni

    Informations forums :
    Inscription : Juin 2006
    Messages : 1 294
    Points : 1 543
    Points
    1 543
    Par défaut
    Ouais ça arrive quand on se goure dans le boost::bind, apparemment msvc s'emmèle dans les templates...
    En l'occurence il manque un _1 en paramètre après le foo je pense.

    MAT.

  9. #9
    Membre chevronné
    Avatar de poukill
    Profil pro
    Inscrit en
    Février 2006
    Messages
    2 155
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France

    Informations forums :
    Inscription : Février 2006
    Messages : 2 155
    Points : 2 107
    Points
    2 107
    Par défaut
    Citation Envoyé par Mat007 Voir le message
    Ouais ça arrive quand on se goure dans le boost::bind, apparemment msvc s'emmèle dans les templates...
    En l'occurence il manque un _1 en paramètre après le foo je pense.
    Oui, c'est exactement ça!
    Euh... pourquoi?

  10. #10
    Membre expérimenté

    Profil pro
    Inscrit en
    Juin 2006
    Messages
    1 294
    Détails du profil
    Informations personnelles :
    Localisation : Royaume-Uni

    Informations forums :
    Inscription : Juin 2006
    Messages : 1 294
    Points : 1 543
    Points
    1 543
    Par défaut
    Citation Envoyé par poukill Voir le message
    Euh... pourquoi?
    Pourquoi faut mettre _1 ?
    C'est ce qu'expliquait HanLee, c'est un placeholder qui indique où il faudra passer le premier paramètre de l'appel au foncteur (premier car _1).
    Comme 'applyTreatment' est une fonction membre (et non une fonction libre) il faut préciser sur quelle instance appliquer (ici c'est 'foo') puis ensuite donner les paramètres à passer, autant que nécessaire à 'applyTreatment', une combinaison de valeurs (elles vont toutes être copiées puisque c'est la sémantique des foncteurs, d'où les boost::ref etc..) et de placeholders.

    MAT.

  11. #11
    Membre chevronné
    Avatar de poukill
    Profil pro
    Inscrit en
    Février 2006
    Messages
    2 155
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France

    Informations forums :
    Inscription : Février 2006
    Messages : 2 155
    Points : 2 107
    Points
    2 107
    Par défaut
    OK Merci pour les explications HanLee et Mat007 !

  12. #12
    Expert confirmé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Décembre 2003
    Messages
    3 549
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

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

    Informations forums :
    Inscription : Décembre 2003
    Messages : 3 549
    Points : 4 625
    Points
    4 625
    Par défaut
    Puisqu'apparemment tu as du mal à comprendre boost.bind (et boost.function), je te conseille dans un premier temps d'écrire tes foncteurs à la main.
    Boost ftw

  13. #13
    Membre chevronné
    Avatar de poukill
    Profil pro
    Inscrit en
    Février 2006
    Messages
    2 155
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France

    Informations forums :
    Inscription : Février 2006
    Messages : 2 155
    Points : 2 107
    Points
    2 107
    Par défaut
    Citation Envoyé par loufoque Voir le message
    Puisqu'apparemment tu as du mal à comprendre boost.bind (et boost.function), je te conseille dans un premier temps d'écrire tes foncteurs à la main.
    WoW! Euh, c'est une bonne idée Loufoque... Une piste pour commencer peut-être?

  14. #14
    Alp
    Alp est déconnecté
    Expert éminent sénior

    Avatar de Alp
    Homme Profil pro
    Inscrit en
    Juin 2005
    Messages
    8 575
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Juin 2005
    Messages : 8 575
    Points : 11 860
    Points
    11 860
    Par défaut
    Pour ce qui concerne les foncteurs, la FAQ C++ en parle. Tu comprendras pourquoi loufoque t'a donné cette idée.

    Ensuite, en travaillant comme il se doit le tutoriel et les exemples de boost.bind, tu n'arriverais toujours à rien ? N'hésite pas à passer du temps dessus.

  15. #15
    Membre chevronné
    Avatar de poukill
    Profil pro
    Inscrit en
    Février 2006
    Messages
    2 155
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France

    Informations forums :
    Inscription : Février 2006
    Messages : 2 155
    Points : 2 107
    Points
    2 107
    Par défaut
    Oui les foncteurs je connais, quand même !!!
    J'ai déjà pas mal bossé sur les unary fonctors, binary fonctors etc... grâce notamment à la bibliothèque Vigra...
    Maintenant c'est vrai que les bind m'étaient totalement inconnu, je crois que j'ai encore un peu de boulot de ce côté!

    Non pour l'instant je n'ai bossé que les Thread et fonction récemment chez Boost. Je vais regarder boost.bind de ce pas !!!! (j'ai pas encore eu le temps, je suis dans un gros projet là ! )


    Merci de vos conseils à tous en tous cas !

  16. #16
    Expert confirmé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Décembre 2003
    Messages
    3 549
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

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

    Informations forums :
    Inscription : Décembre 2003
    Messages : 3 549
    Points : 4 625
    Points
    4 625
    Par défaut
    Par exemple, écrire boost::bind(&Type::fonction, boost::ref(obj), _1)

    C'est plus ou moins équivalent à écrire (il me semble)

    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
    struct functor
    {
        Type& obj;
     
        functor(Type& obj_) : obj(obj_)
        {
        }
     
        template<typename T>
        void operator()(T& t) const
        {
            obj.fonction(t);
        }
    };
     
    // puis pour instancier le foncteur
     
    functor(obj);
    Boost ftw

  17. #17
    Alp
    Alp est déconnecté
    Expert éminent sénior

    Avatar de Alp
    Homme Profil pro
    Inscrit en
    Juin 2005
    Messages
    8 575
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Juin 2005
    Messages : 8 575
    Points : 11 860
    Points
    11 860
    Par défaut
    Le T ne devrait pas être pris par référence ?

  18. #18
    Expert confirmé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Décembre 2003
    Messages
    3 549
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

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

    Informations forums :
    Inscription : Décembre 2003
    Messages : 3 549
    Points : 4 625
    Points
    4 625
    Par défaut
    En effet, tu as raison.
    Boost ftw

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

Discussions similaires

  1. Réponses: 5
    Dernier message: 06/04/2011, 10h02
  2. appel à une fonction static externe
    Par marion5515 dans le forum Débuter
    Réponses: 1
    Dernier message: 09/07/2010, 11h53
  3. Réponses: 12
    Dernier message: 12/05/2006, 09h21

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