Bienvenue, Invité. Merci de vous connecter ou de vous inscrire.
Avez-vous perdu votre e-mail d'activation ?

Auteur Sujet: Juste une petite question sur le c++ d'ordre général.  (Lu 2324 fois)

0 Membres et 1 Invité sur ce sujet

Lolilolight

  • Hero Member
  • *****
  • Messages: 1232
    • Voir le profil
Juste une petite question sur le c++ d'ordre général.
« le: Janvier 05, 2014, 10:49:26 am »
Salut, j'aimerais savoir si il y a moyen de passer des références à un tuple et de les extraires : (Car ce code-ci marche bien mais, lorsque je veux utiliser des références le type de l'objet renvoyé par bind change, ce n'est plus un std::function mais un std::_BindHelper marchin quelque chose :

std::function<void(Ex&, std::string)> f1 = std::bind(&Ex::of, obj, "1");
    Slot<void, std::function<void(Ex&, std::string)>> s1(f1);
    s1(obj, "1");
//Ne marche pas!
std::function<void(Ex&, std::string&)> f2 = std::bind(&Ex::of, obj, "1");
    Slot<void, std::function<void(Ex&, std::string&)>> s2(f2);
    s2(obj, "1");
 

Alors j'ai essayer de créer mon propre binder et de faire ça :

#ifndef BIND_H
#define BIND_H

#include "function.h"

#include <tuple>
namespace sfgl {
    namespace helper {
        template<int ...> struct seq {};

        template<int N, int ...S> struct gens : gens<N-1, N-1, S...> {};

        template<int ...S> struct gens<0, S...>{ typedef seq<S...> type; };
    }
    template <typename R> class Bind {
    };
    template <typename R, typename... A> class Bind <R(A...)> {
        public :
        Bind (R(*f)(A...) , A... args) : function(f)  {
            params = std::make_tuple(args...);
        }

        template<int ...S>
        R operator ()(A... args) {
            params = std::make_tuple(args...);
            return callFunc(typename helper::gens<sizeof...(A)>::type());
        }
        template<int ...S>
        R operator ()() {
            //R(*func)(A...) = *reinterpret_cast<R**>(function);
            return callFunc(typename helper::gens<sizeof...(A)>::type());
        }
        template<int ...S>
        R callFunc(helper::seq<S...>)
        {
            return function(std::get<S>(params)...);
        }
        //private :
        std::tuple <A...> params;
        R(*function)(A...);
    };
    template <typename R, typename O, typename... A> class Bind <R(O&, A...)> {
        public:
        Bind (R(O::*f)(A...), O object, A... args) : object(object), function(f) {
            params = std::make_tuple(args...);
        }
        void changeParams (A... args) {
            params = std::make_tuple(args...);
        }
        R operator ()(A... args) {
            params = std::make_tuple(args...);
            return callFunc(typename helper::gens<sizeof...(A)>::type());
        }
        template<int ...S>
        R operator ()() {
            return callFunc(typename helper::gens<sizeof...(A)>::type());
        }
        template<int ...S>
        R callFunc(helper::seq<S...>)
        {
            return (object.*function)(std::get<S>(params)...);
        }
        //private :
        O object;
        std::tuple <A...> params;
        R(O::*function)(A...);
    };
}
#endif // BIND
 

Malheureusement, ça ne fonctionne pas lorsque je veux passer des références à mon slot.

Je sais que il faut utiliser un std::reference_wrapper mais je ne vois pas comment l'utiliser avec les templates variadique..., afin de faire un tuple qui puisse stocker aussi bien des références que des pointeurs.

Bref le but final est d'essayer de faire un binder dont le type ne change pas (que ce soit lorsque j'utilise des références, ou bien des placeholders...)

Bind<void(Ex&, std::string)> b1 (&Ex::of,obj, _1);
    Slot<void, Bind<void(Ex&, std::string)>> s1 (b1);
    s1("1");
Bind<void(Ex&, std::string&)> b2 (&Ex::of,obj, _1);
    Slot<void, Bind<void(Ex&, std::string)>> s2 (b2);
    s2(std::ref("1"));
 

Mais je ne sais pas si c'est possible de faire quelque chose comme ça.

Au pire je mettrai des arguments bidons lors de la création de mon binder si j'en ai pas besoin lors de l'appel du slot que je remplacerai à l'appel du slot, et je n'auriserai pas le passage par référence qui me pose problème mais que par pointeur.
« Modifié: Janvier 05, 2014, 10:54:35 am par Lolilolight »

Lolilolight

  • Hero Member
  • *****
  • Messages: 1232
    • Voir le profil
Re : Juste une petite question sur le c++ d'ordre général.
« Réponse #1 le: Janvier 05, 2014, 06:05:53 pm »
Sinon, je voudrais stocker un pointeur sur une lambda expression, mais il me semble qu'en c++ ce n'est pas possible, je voudrais en fait faire quelque chose comme ceci :


namespace sfgl {
class  System {
    public :
        template <typename R, typename F, typename ...A> static void connect (std::string id, Slot<R, F> slot, A... args) {
            idsToFunctions.insert(std::pair<std::string, std::function<void()>>(id,slot.make_callback(args...)));
        }

        template <typename ...A> static void emit (std::string id, A... args) {
            itToF = idsToFunctions.find(id);
            if (itToF != idsToFunctions.end()) {
                itToF->second(args...);
            } else
                throw Erreur (20, "Slot not found!", 0);
        }
    private :
        static std::map<std::string, std::function<void()>> idsToFunctions;
        static std::map<std::string, std::function<void()>>::iterator itToF;
};
std::map<std::string, std::function<void()>> System::idsToFunctions = std::map<std::string, std::function<void()>> ();
std::map<std::string, std::function<void()>>::iterator System::itToF = idsToFunctions.begin();
}
#endif // OBJECT
 
#ifndef PLACE_HOLDERS_H
#define PLACE_HOLDERS_H
#include "bind.h"
namespace sfgl {
template <typename R, typename F> class Slot {
    public :
        Slot (F f) : function(f) {}

        template <typename ...A> R operator()(A... args) {
            return function(args...);
        }
        template <typename ...A> std::function<void()> make_callback (A... args) {
            std::function<void(A...)> *f = new std::function<void(A...)> (
                [
                    this
                ] (A... args) {

                    (*this)(args...);
                }
            );
            return std::function<void()> (f);
        }
    private :
    F function;
};
}
#endif // PLACE_HOLDERS_H
 

Mais j'aimerais pouvoir stocker dans ma map, n'importe quel type de lambda expression. (Avec un nombre variable d'arguments surtout!)

Quelqu'un sait t'il pour quand c'est prévu les pointeurs sur des lambdas expressions ?
« Modifié: Janvier 05, 2014, 06:08:36 pm par Lolilolight »

Lolilolight

  • Hero Member
  • *****
  • Messages: 1232
    • Voir le profil
Re : Juste une petite question sur le c++ d'ordre général.
« Réponse #2 le: Janvier 06, 2014, 01:28:05 pm »
Bon bah je crois que j'ai trouvé une solution alternative au problème :

Je créer une fonction non membre callback qui appelle n'importe quel type de pointeur de fonction :

template <typename R> class Functor {
};
template<typename R, typename F> class Functor<R(F)> {
    public :

    template <typename... A>  Functor(R(*f)(F, A...), F funct, A... args) : funct(funct), function(&f) {

    }

    template <typename... A> R operator()(A... args) {
        R(*func)(F, A...) = *reinterpret_cast<R**>(function);
        return  func(funct, args...);
    }

    private :
    F funct;
    R** function;

};
 

Et ensuite une classe "Factory" qui sert à créer un pointeur de fonction sur ma fonction de callback :

#ifndef PLACE_HOLDERS_H
#define PLACE_HOLDERS_H
#include "bind.h"
namespace sfgl {
template <typename F, typename ...A> void callback (F func, A... args) {
    std::cout<<"call back"<<std::endl;
    func(args...);
}

template <typename R, typename F> class Slot {
    public :
        Slot (F f) : function(f) {}
        template <typename ...A> R operator()(A... args) {
            return function(args...);
        }

        template <typename ...A> Functor<void(F)> make_callback (A... args) {
            typedef void(*CB)(F, A...);
            CB cb = &callback;
            Functor<void(F)> funct (cb, function, args...);
            return funct;
        }
    private :
    F function;
};
}
#endif // PLACE_HOLDERS_H
 

Ce code source est puissant car il accepte n'importe quel type d'objet appelant une fonction membre ou non membre (std::function, sfgl::bind, etc...), mais il reste un problème, comment stocké mes foncteurs dans une std::map à l'aide d'une clé.

J'ai trouvé un design pattern intéressant qui pourrait peut être m'aider :

http://come-david.developpez.com/tutoriels/dps/?page=Fabrique
« Modifié: Janvier 06, 2014, 01:29:38 pm par Lolilolight »

Laurent

  • Administrator
  • Hero Member
  • *****
  • Messages: 32498
    • Voir le profil
    • SFML's website
    • E-mail
Re : Juste une petite question sur le c++ d'ordre général.
« Réponse #3 le: Janvier 06, 2014, 09:30:02 pm »
Tu recommences à prendre ce forum pour ton blog.
Laurent Gomila - SFML developer