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

Langage C++ Discussion :

Quelques questions à propos du langage lui même.


Sujet :

Langage C++

  1. #61
    Invité
    Invité(e)
    Par défaut
    Houla ça dépasse largement de mes compétences tout ça.

    En gros je vais devoir faire un wrapper pour chaque type (reference, placeholder, etc...), et les mettre dans le tuple ? (Et appeler les fonctions via des classes de politique et boost::mpl ?)

    Je pense que il y a moyen via une spécialsiation de template mais ça dépasse mes compétences.

    De plus comme j'ai besoin de stocker les types dans une classe, je vois pas comment faire un tuple en ne connaissant pas les types des wrappers lors de la déclaration de la classe...

    A moins de faire un truc comme ça ?

    Code cpp : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    template <typename... A>
    DynamicDelegate {
    };
    template <typename H, typename... T>
    DynamicDelegate<genericWrapper<H>, genericWrapper<T>...> {
    };

    Et un make qui wrap le type de chaque élément du tuple, et qui applique type erasure pour retourner le bon type, mais je sais pas si ça va marcher, je dois avouer que je sèche pas mal sur ce point, et j'ai pas vraiment d'idée pour l'instant.

    std::decay ça fait quoi ça converti tout en valeur ?

    Ca marcherait pas pour les pointeurs ça, si ?

    Bref je vois vraiment pas comment faire ça pour tout les types (références, pointeurs et simple variable), pour le type de retour ça va je vois mais pour le reste. :/
    Pour le reste va falloir itérer, trouver le bon wrapper, ça m'a l'air galère à faire ça. :/

  2. #62
    Invité
    Invité(e)
    Par défaut
    Et je suis obligé de passer par boost ?

    Les std::is_same, std::is_convertible et tout ça ne suffisent pas ?

    Ca me fait fort penser à des classes de polytique boost::mpl. (Ou bien à des classes de trait)

  3. #63
    En attente de confirmation mail

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2004
    Messages
    1 391
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France, Doubs (Franche Comté)

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

    Informations forums :
    Inscription : Août 2004
    Messages : 1 391
    Points : 3 311
    Points
    3 311
    Par défaut
    J'aurais pas du mettre les classes de politique, ca t'embrouille plus qu'autre chose à priori. Je suis passé par des classes de politique pour offrir le comportement que tu désires (ton dynamic_cast automatique et la prise en charge des const char*) tout en pouvant revenir à un comportement plus classique et simple.

    Mais oui ce que tu veux faire est galère et compliqué, mais là tu arrives sur des galères que tu aurais eu avec ton ancien code. Je peux resimplifier le code (donc pas de prise en charge de dynamic_cast automatique ou des const char*) pour avancer sur le reste :
    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
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
     
    #include<functional>
    #include<memory>
    #include<tuple>
    #include<type_traits>
    #include<utility>
     
    namespace odfaeg {
     
    template<class R>
    struct Delegate {
    	Delegate() =default;
    	virtual std::unique_ptr<Delegate> clone() const = 0;
    	virtual R operator()() const = 0;
    	virtual ~Delegate(){}
    protected:
    	Delegate(const Delegate&){}
    	Delegate& operator=(const Delegate&)
    	{ return *this; }
    };
     
    template<class R, class... ArgT>
    struct FastDelegateImpl : Delegate<R> {
    	template<class F, class... ArgU>
    	FastDelegateImpl(F&& f, ArgU&&... arg)
    		: func(std::forward<F>(f))
    		, param(std::forward<ArgU>(arg)...)
    	{}
    	std::unique_ptr<Delegate<R>> clone() const
    	{ return std::make_unique<FastDelegateImpl>(*this); }
    	R operator()() const
    	{ return call(std::make_index_sequence<sizeof...(ArgT)>()); }
    	template<class... ArgU>
    	void setParam(ArgU&&... arg)
    	{ param=std::make_tuple(std::forward<ArgU>(arg)...); }
     
    private:
    	template<std::size_t... I>
    	R call(std::index_sequence<I...>) const
    	{ return func(std::get<I>(param)...); }
     
    	std::function<R(ArgT...)> func;
    	std::tuple<ArgT...> param;
    };
     
    template<class R>
    struct FastDelegate {
    	template<class F, class... Arg>
    	FastDelegate(F&& f, Arg&&... arg) :
    		delegate(std::make_unique<FastDelegateImpl<R,Arg...>>
    			(std::forward<F>(f),std::forward<Arg>(arg)...)
    		)
    	{}
    	FastDelegate(FastDelegate& rhs)
    		: delegate(rhs.delegate->clone())
    	{}
    	FastDelegate(const FastDelegate& rhs)
    		: delegate(rhs.delegate->clone())
    	{}
    	FastDelegate(FastDelegate&& rhs) =default;
    	FastDelegate& operator=(const FastDelegate& rhs)
    	{ return operator=(FastDelegate(rhs)); }
    	FastDelegate& operator=(FastDelegate&&) =default;
    	R operator()() const
    	{ return (*delegate)(); }
    	template<class... Arg>
    	void setParam(Arg&&... arg)
    	{
    		using DynamicType = FastDelegateImpl<R,Arg...>*;
     
    		if(dynamic_cast<DynamicType>(delegate.get()))
    			dynamic_cast<DynamicType>(delegate.get())->setParam(std::forward<Arg>(arg)...);
    	}
     
    private:
    	std::unique_ptr<Delegate<R>> delegate;
    };
     
    }
    Avec un peu moins de cas d'utilisation donc :
    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
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
     
    #include<iostream>
    #include<string>
     
    using namespace std::literals;
     
    void foo(int i)
    { std::cout << i; }
     
    struct A {
    	void foo(int i)
    	{ std::cout << i; }
    };
     
    struct D {
    	void operator()(int i) const
    	{ std::cout << i; }
    };
     
    void bar(const std::string& s)
    { std::cout << s; }
     
    int goo(int i)
    { return i; }
     
    int main(){
    	odfaeg::FastDelegate<void> f1(foo,1);
    	f1();
    	f1.setParam(2);
    	f1();
    	std::cout << std::endl;
     
    	odfaeg::FastDelegate<void> f2(
    		[](int i){ std::cout << i; },
    		3
    	);
    	f2();
    	f2.setParam(4);
    	f2();
    	std::cout << std::endl;
     
    	int i = 5;
    	odfaeg::FastDelegate<void> f3(
    		[i](int j){ std::cout << i << j; },
    		6
    	);
    	f3();
    	f3.setParam(7);
    	f3();
    	std::cout << std::endl;
     
    	A a;
    	odfaeg::FastDelegate<void> f4(&A::foo,&a,8);
    	f4();
    	f4.setParam(&a,9);
    	f4();
    	std::cout << std::endl;
     
    	odfaeg::FastDelegate<void> f5 = f1;
    	f5();
    	f5=f2;
    	f5();
    	std::cout << std::endl;
     
    	odfaeg::FastDelegate<void> f6(D(),10);
    	f6();
    	f6.setParam(11);
    	f6();
    	std::cout << std::endl;
     
    	odfaeg::FastDelegate<void> f7(bar,"ab"s);
    	f7();
    	f7.setParam("abc"s);
    	f7();
    	std::cout << std::endl;
     
    	odfaeg::FastDelegate<int> f8(goo,12);
    	std::cout << f8();
    	f8.setParam(13);
    	std::cout << f8();
    	std::cout << std::endl;
    }
    Si tu comprends l'ensemble de ce code (chaque ligne), on peut avancer sur les autres problématiques, puis quand elles seront résolus, réintroduire ton dynamic_cast ne devrait te poser aucun problème.

    Non tu n'es pas obligé de passer par boost.mpl, mais faire des bouts de méta-programmation template sans lui c'est marrant deux minutes, après on utilise ce qui marche et est éprouvé (comme std::function ça marche bien alors on hésite pas, on l'utilise avant de tout refaire à la main).

    Les problématiques réelles qui reste c'est :
    • Permettre de ne changer qu'un élément du tuple
    • Permettre de passer des reference_wrapper dans le tupe
    • Permettre de passer des placeholders dans le tuple

    Et ces trois éléments sont liés, mais il faut vraiment que tu ai bien compris le code que j'ai mis dans ce message pour commencer à les traiter.

  4. #64
    Invité
    Invité(e)
    Par défaut
    Ok, je vais essayer de comprendre ça! (De toute façon j'y arriverai bien si j'arrive à recoder std::function et la plupart des grosses libs à la main, enfin, avec un peu de difficultés lors de la méta programmation quand même mais c'est la 1ère fois que je touche à ça. (J'ai commencé le c++11 il y a quelque mois seulement et boost j'y ai jamais touché.)

    Et puis, je verrai ce que je peux faire pour les autres cas!

    En tout cas ça me semble carrément être un autre langage surtout que je ne devais pas gérer tout ça lorsque j'ai appris en java. (Qui est, mon premier langage OO)

    Et bon même si ça permet de faire des choses plus générique, le c++98 est quand même plus simple appréhender surtout au niveau de la syntaxe. ^^

    Le c++11 ne m'a pas donné envie au départ, les [](){} et les A..., A&&, etc..., ainsi que les récursions sur les structures (à la place des fonctions) ça me disait vraiment rien.
    Dernière modification par Invité ; 05/09/2014 à 22h19.

  5. #65
    Invité
    Invité(e)
    Par défaut
    Re, pour le code que tu m'as posté plus haut ça va je comprend, et il est vrai que je pourrai aisément réduire le nombre de classes.

    C'est ce bout de code là que je ne comprend pas :

    Code cpp : 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
     
    template<class... ArgT>
    class DynamicFunction<void(ArgT...)>
    	: std::function<void(ArgT...)>
    {
    	using Base = std::function<void(ArgT...)>;
     
    public:
    	template<class F>
    	DynamicFunction(F&& f) : Base(std::forward<F>(f))
    	{}
    	template<class C, class... ArgU>
    	DynamicFunction(void (C::*pf)(ArgU...))
    		: Base(DynamicWrapper<C,ArgU...>(pf))
    	{}
     
    	using Base::operator();
    };

    Et surtout, le deuxième constructeur, tu passes un objet de type DynamicWrapper au constructeur d'un std::function, pourquoi est ce que ça marche ? :o

    (Je ne savais pas du tout que l'on pouvait faire ça, si je l'avais su je l'aurai déjà fais.)

    De plus j'ai essayé de spécialiser le code avec la fonction dynamique mais ça ne fonctionne pas. :/

    Code cpp : 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
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
     
    #include <functional>
    #include <memory>
    #include <utility>
    namespace odfaeg {
    typedef void DefaultVoid;
    template<class R, class C, class... ArgT>
    struct DynamicWrapper {
    	DynamicWrapper(R(C::*pf)(ArgT...)) : pfunc(pf){}
    	template<class O, class... ArgU>
    	R operator()(O* o, ArgU&&... arg) const
    	{
    		if(dynamic_cast<C*>(o))
    			return (dynamic_cast<C*>(o)->*pfunc)(std::forward<ArgU>(arg)...);
    	}
    private:
    	R (C::*pfunc)(ArgT...);
    };
    template<class C, class... ArgT>
    struct DynamicWrapper <void, C, ArgT...> {
    	DynamicWrapper(void(C::*pf)(ArgT...)) : pfunc(pf){}
    	template<class O, class... ArgU>
    	void operator()(O* o, ArgU&&... arg) const
    	{
    		if(dynamic_cast<C*>(o))
    			(dynamic_cast<C*>(o)->*pfunc)(std::forward<ArgU>(arg)...);
    	}
    private:
    	void (C::*pfunc)(ArgT...);
    };
    template<class F>
    class DynamicFunction;
     
    template<class R, class... ArgT>
    class DynamicFunction<R(ArgT...)>
    	: std::function<R(ArgT...)>
    {
    	using Base = std::function<R(ArgT...)>;
     
    public:
    	template<class F>
    	DynamicFunction(F&& f) : Base(std::forward<F>(f))
    	{}
    	template<class C, class... ArgU>
    	DynamicFunction(R (C::*pf)(ArgU...))
    		: Base(DynamicWrapper<R,C,ArgU...>(pf))
    	{}
     
    	using Base::operator();
    };
    template<class... ArgT>
    class DynamicFunction<void(ArgT...)>
    	: std::function<void(ArgT...)> {
     
    	using Base = std::function<void(ArgT...)>;
     
    public:
    	template<class F>
    	DynamicFunction(F&& f) : Base(std::forward<F>(f))
    	{}
    	template<class C, class... ArgU>
    	DynamicFunction(void (C::*pf)(ArgU...))
    		: Base(DynamicWrapper<C,ArgU...>(pf))
    	{}
     
    	using Base::operator();
    };
    template <typename R>
    struct Delegate {
    	Delegate() =default;
    	virtual std::unique_ptr<Delegate<R>> clone() const = 0;
    	virtual R operator()() const = 0;
    	virtual ~Delegate();
    protected:
    	Delegate(const Delegate&){}
    	Delegate& operator=(const Delegate&)
    	{ return *this; }
    };
    template <typename R>
    Delegate<R>::~Delegate(){}
    template <>
    struct Delegate<void> {
    	Delegate() =default;
    	virtual std::unique_ptr<Delegate<void>> clone() const = 0;
    	virtual void operator()() const = 0;
    	virtual ~Delegate();
    protected:
    	Delegate(const Delegate&){}
    	Delegate& operator=(const Delegate&)
    	{ return *this; }
    };
    Delegate<void>::~Delegate(){}
    template<class R, class... ArgT>
    struct FastDelegateImpl : Delegate<R> {
    	template<class F, class... ArgU>
    	FastDelegateImpl(F&& f, ArgU&&... arg)
    		: func(std::forward<F>(f))
    		, param(std::forward<ArgU>(arg)...)
    	{}
    	std::unique_ptr<Delegate<R>> clone() const
    	{ return std::make_unique<FastDelegateImpl>(*this); }
    	R operator()() const
    	{ return call(std::make_index_sequence<sizeof...(ArgT)>()); }
    	template<class... ArgU>
    	void setParam(ArgU&&... arg)
    	{ param=std::make_tuple(std::forward<ArgU>(arg)...); }
     
    private:
    	template<std::size_t... I>
    	R call(std::index_sequence<I...>) const
    	{ return func(std::get<I>(param)...); }
    	DynamicFunction<void(ArgT...)> func;
    	std::tuple<ArgT...> param;
    };
    template<class... ArgT>
    struct FastDelegateImpl<void, ArgT...> : Delegate<void> {
    	template<class F, class... ArgU>
    	FastDelegateImpl(F&& f, ArgU&&... arg)
    		: func(std::forward<F>(f))
    		, param(std::forward<ArgU>(arg)...)
    	{}
    	std::unique_ptr<Delegate<void>> clone() const
    	{ return std::make_unique<FastDelegateImpl>(*this); }
    	void operator()() const
    	{ call(std::make_index_sequence<sizeof...(ArgT)>()); }
    	template<class... ArgU>
    	void setParam(ArgU&&... arg)
    	{ param=std::make_tuple(std::forward<ArgU>(arg)...); }
     
    private:
    	template<std::size_t... I>
    	void call(std::index_sequence<I...>) const
    	{ func(std::get<I>(param)...); }
    	DynamicFunction<void(ArgT...)> func;
    	std::tuple<ArgT...> param;
    };
    template <typename R>
    struct FastDelegate {
    	template<class F, class... Arg>
    	FastDelegate(F&& f, Arg&&... arg) :
    		delegate(std::make_unique<FastDelegateImpl<R, Arg...>>
    			(std::forward<F>(f),std::forward<Arg>(arg)...)
    		)
    	{}
    	FastDelegate(FastDelegate& rhs) : delegate(rhs.delegate->clone())
    	{}
    	FastDelegate(const FastDelegate& rhs) : delegate(rhs.delegate->clone())
    	{}
    	FastDelegate(FastDelegate&& rhs) =default;
    	FastDelegate& operator=(const FastDelegate& rhs)
    	{ return operator=(FastDelegate(rhs)); }
    	FastDelegate& operator=(FastDelegate&&) =default;
    	R operator()() const
    	{ (*delegate)(); }
    	template<class... Arg>
    	void setParam(Arg&&... arg)
    	{
    		using DynamicType = FastDelegateImpl<R, Arg...>*;
     
    		if(dynamic_cast<DynamicType>(delegate.get()))
    			dynamic_cast<DynamicType>(delegate.get())->setParam(std::forward<Arg>(arg)...);
    	}
    	void boo(){}
     
    private:
    	std::unique_ptr<Delegate<R>> delegate;
    };
    template <>
    struct FastDelegate<void> {
    	template<class F, class... Arg>
    	FastDelegate(F&& f, Arg&&... arg) :
    		delegate(std::make_unique<FastDelegateImpl<Arg...>>
    			(std::forward<F>(f),std::forward<Arg>(arg)...)
    		)
    	{}
    	FastDelegate(FastDelegate& rhs) : delegate(rhs.delegate->clone())
    	{}
    	FastDelegate(const FastDelegate& rhs) : delegate(rhs.delegate->clone())
    	{}
    	FastDelegate(FastDelegate&& rhs) =default;
    	FastDelegate& operator=(const FastDelegate& rhs)
    	{ return operator=(FastDelegate(rhs)); }
    	FastDelegate& operator=(FastDelegate&&) =default;
    	void operator()() const
    	{ (*delegate)(); }
    	template<class... Arg>
    	void setParam(Arg&&... arg)
    	{
    		using DynamicType = FastDelegateImpl<Arg...>*;
     
    		if(dynamic_cast<DynamicType>(delegate.get()))
    			dynamic_cast<DynamicType>(delegate.get())->setParam(std::forward<Arg>(arg)...);
    	}
    	void boo(){}
     
    private:
    	std::unique_ptr<Delegate<void>> delegate;
    };
    }

    J'ai un problème avec std::make_unique :

    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
     
    ||=== Build: Debug in ODFAEG-DEMO (compiler: GNU GCC Compiler) ===|
    /home/laurent/Développement/Projets-c++/ODFAEG-DEMO/delegate.h||In instantiation of ‘odfaeg::FastDelegate<void>::FastDelegate(F&&, Arg&& ...) [with F = void (&)(int); Arg = {int}]’:|
    /home/laurent/Développement/Projets-c++/ODFAEG-DEMO/main.cpp|26|required from here|
    /home/laurent/Développement/Projets-c++/ODFAEG-DEMO/delegate.h|173|error: no matching function for call to ‘std::unique_ptr<odfaeg::Delegate<void> >::unique_ptr(std::_MakeUniq<odfaeg::FastDelegateImpl<int> >::__single_object)’|
    /home/laurent/Développement/Projets-c++/ODFAEG-DEMO/delegate.h|173|note: candidates are:|
    /usr/include/c++/4.9/bits/unique_ptr.h|228|note: template<class _Up, class> std::unique_ptr<_Tp, _Dp>::unique_ptr(std::auto_ptr<_Up>&&)|
    /usr/include/c++/4.9/bits/unique_ptr.h|228|note:   template argument deduction/substitution failed:|
    /home/laurent/Développement/Projets-c++/ODFAEG-DEMO/delegate.h|173|note:   ‘std::_MakeUniq<odfaeg::FastDelegateImpl<int> >::__single_object {aka std::unique_ptr<odfaeg::FastDelegateImpl<int>, std::default_delete<odfaeg::FastDelegateImpl<int> > >}’ is not derived from ‘std::auto_ptr<_Up>’|
    /usr/include/c++/4.9/bits/unique_ptr.h|220|note: template<class _Up, class _Ep, class> std::unique_ptr<_Tp, _Dp>::unique_ptr(std::unique_ptr<_Up, _Ep>&&)|
    /usr/include/c++/4.9/bits/unique_ptr.h|220|note:   template argument deduction/substitution failed:|
    /usr/include/c++/4.9/bits/unique_ptr.h|205|note: std::unique_ptr<_Tp, _Dp>::unique_ptr(std::unique_ptr<_Tp, _Dp>&&) [with _Tp = odfaeg::Delegate<void>; _Dp = std::default_delete<odfaeg::Delegate<void> >]|
    /usr/include/c++/4.9/bits/unique_ptr.h|205|note:   no known conversion for argument 1 from ‘std::_MakeUniq<odfaeg::FastDelegateImpl<int> >::__single_object {aka std::unique_ptr<odfaeg::FastDelegateImpl<int>, std::default_delete<odfaeg::FastDelegateImpl<int> > >}’ to ‘std::unique_ptr<odfaeg::Delegate<void> >&&’|
    /usr/include/c++/4.9/bits/unique_ptr.h|200|note: constexpr std::unique_ptr<_Tp, _Dp>::unique_ptr(std::nullptr_t) [with _Tp = odfaeg::Delegate<void>; _Dp = std::default_delete<odfaeg::Delegate<void> >; std::nullptr_t = std::nullptr_t]|
    /usr/include/c++/4.9/bits/unique_ptr.h|200|note:   no known conversion for argument 1 from ‘std::_MakeUniq<odfaeg::FastDelegateImpl<int> >::__single_object {aka std::unique_ptr<odfaeg::FastDelegateImpl<int>, std::default_delete<odfaeg::FastDelegateImpl<int> > >}’ to ‘std::nullptr_t’|
    J'ai pas mis toutes les erreurs sinon, message trop long.

    std::make_unique me choisi FastDelegateImpl<int> et pas FastDelegateImpl<void> comme il devrait.
    Dernière modification par Invité ; 06/09/2014 à 10h34.

  6. #66
    Invité
    Invité(e)
    Par défaut
    Bon c'est bon j'ai compris! (J'ai retiré la spécialisation car std::make_unique ne peux pas deviner quelle spécialisation utiliser pour le clonage)
    Code cpp : 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
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
     
    #include <functional>
    #include <memory>
    #include <utility>
    namespace odfaeg {
    typedef void DefaultVoid;
    template<class R, class C, class... ArgT>
    struct DynamicWrapper {
    	DynamicWrapper(R(C::*pf)(ArgT...)) : pfunc(pf){}
    	template<class O, class... ArgU>
    	R operator()(O* o, ArgU&&... arg) const
    	{
    		if(dynamic_cast<C*>(o))
    			return (dynamic_cast<C*>(o)->*pfunc)(std::forward<ArgU>(arg)...);
    	}
    private:
    	R (C::*pfunc)(ArgT...);
    };
    template<class F>
    class DynamicFunction;
     
    template<class R, class... ArgT>
    class DynamicFunction<R(ArgT...)>
    	: std::function<R(ArgT...)>
    {
    	using Base = std::function<R(ArgT...)>;
     
    public:
    	template<class F>
    	DynamicFunction(F&& f) : Base(std::forward<F>(f))
    	{}
    	template<class C, class... ArgU>
    	DynamicFunction(R (C::*pf)(ArgU...))
    		: Base(DynamicWrapper<R,C,ArgU...>(pf))
    	{}
     
    	using Base::operator();
    };
    template <typename R>
    struct Delegate {
    	Delegate() =default;
    	virtual std::unique_ptr<Delegate> clone() const = 0;
    	virtual R operator()() const = 0;
    	virtual ~Delegate();
    protected:
    	Delegate(const Delegate&){}
    	Delegate& operator=(const Delegate&)
    	{ return *this; }
    };
    template <typename R>
    Delegate<R>::~Delegate(){}
    template<class R, class... ArgT>
    struct FastDelegateImpl : Delegate<R> {
    	template<class F, class... ArgU>
    	FastDelegateImpl(F&& f, ArgU&&... arg)
    		: func(std::forward<F>(f))
    		, param(std::forward<ArgU>(arg)...)
    	{}
    	std::unique_ptr<Delegate<R>> clone() const
    	{ return std::make_unique<FastDelegateImpl>(*this); }
    	R operator()() const
    	{ return call(std::make_index_sequence<sizeof...(ArgT)>()); }
    	template<class... ArgU>
    	void setParam(ArgU&&... arg)
    	{ param=std::make_tuple(std::forward<ArgU>(arg)...); }
     
    private:
    	template<std::size_t... I>
    	R call(std::index_sequence<I...>) const
    	{ return func(std::get<I>(param)...); }
    	DynamicFunction<R(ArgT...)> func;
    	std::tuple<ArgT...> param;
    };
    template <typename R>
    struct FastDelegate {
    	template<class F, class... Arg>
    	FastDelegate(F&& f, Arg&&... arg) :
    		delegate(std::make_unique<FastDelegateImpl<R, Arg...>>
    			(std::forward<F>(f),std::forward<Arg>(arg)...)
    		)
    	{}
    	FastDelegate(FastDelegate& rhs) : delegate(rhs.delegate->clone())
    	{}
    	FastDelegate(const FastDelegate& rhs) : delegate(rhs.delegate->clone())
    	{}
    	FastDelegate(FastDelegate&& rhs) =default;
    	FastDelegate& operator=(const FastDelegate& rhs)
    	{ return operator=(FastDelegate(rhs)); }
    	FastDelegate& operator=(FastDelegate&&) =default;
    	R operator()() const
    	{ (*delegate)(); }
    	template<class... Arg>
    	void setParam(Arg&&... arg)
    	{
    		using DynamicType = FastDelegateImpl<R, Arg...>*;
     
    		if(dynamic_cast<DynamicType>(delegate.get()))
    			dynamic_cast<DynamicType>(delegate.get())->setParam(std::forward<Arg>(arg)...);
    	}
    	void boo(){}
     
    private:
    	std::unique_ptr<Delegate<R>> delegate;
    };
    }

    Ce qui revient à ton ancien code, j'ai retiré boost::mpl que je ne comprend pas très bien, donc, je vais regarder de ce côté là et je vais essayer de l'utiliser pour les références et les placeholders.

    PS : je pense que je vais utiliser "abc"s, ça m'a l'air beaucoup plus pratique.

  7. #67
    En attente de confirmation mail

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2004
    Messages
    1 391
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France, Doubs (Franche Comté)

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

    Informations forums :
    Inscription : Août 2004
    Messages : 1 391
    Points : 3 311
    Points
    3 311
    Par défaut
    Très bien, avançons un peu, d'abord quelques modification :
    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
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
     
    namespace odfaeg {
     
    template<class R>
    struct Delegate {
    	Delegate() =default;
    	virtual std::unique_ptr<Delegate> clone() const = 0;
    	virtual R operator()() = 0;
    	virtual ~Delegate(){}
    protected:
    	Delegate(const Delegate&){}
    	Delegate& operator=(const Delegate&)
    	{ return *this; }
    };
     
    template<class R, class... ArgT>
    struct FastDelegateImpl : Delegate<R> {
    	template<class F, class... ArgU>
    	FastDelegateImpl(F&& f, ArgU&&... arg)
    		: func(std::forward<F>(f))
    		, param(std::forward<ArgU>(arg)...)
    	{}
    	std::unique_ptr<Delegate<R>> clone() const
    	{ return std::make_unique<FastDelegateImpl>(*this); }
    	R operator()()
    	{ return call(std::make_index_sequence<sizeof...(ArgT)>()); }
    	template<class... ArgU>
    	void setParam(ArgU&&... arg)
    	{ param=std::make_tuple(std::forward<ArgU>(arg)...); }
     
    private:
    	template<std::size_t... I>
    	R call(std::index_sequence<I...>)
    	{ return func(std::get<I>(param)...); }
     
    	std::function<R(ArgT&...)> func;
    	std::tuple<ArgT...> param;
    };
     
    template<class R>
    struct FastDelegate {
    	template<class F, class... Arg>
    	FastDelegate(F&& f, Arg&&... arg) :
    		delegate(std::make_unique
    			<FastDelegateImpl<R,typename std::remove_reference<Arg>::type...>>
    			(std::forward<F>(f),std::forward<Arg>(arg)...)
    		)
    	{}
    	FastDelegate(FastDelegate& rhs)
    		: delegate(rhs.delegate->clone())
    	{}
    	FastDelegate(const FastDelegate& rhs)
    		: delegate(rhs.delegate->clone())
    	{}
    	FastDelegate(FastDelegate&& rhs) =default;
    	FastDelegate& operator=(const FastDelegate& rhs)
    	{ return operator=(FastDelegate(rhs)); }
    	FastDelegate& operator=(FastDelegate&&) =default;
    	R operator()() const
    	{ return (*delegate)(); }
    	template<class... Arg>
    	void setParam(Arg&&... arg)
    	{
    		using DynamicType =
    			FastDelegateImpl<R,typename std::remove_reference<Arg>::type...>*;
     
    		if(dynamic_cast<DynamicType>(delegate.get()))
    			dynamic_cast<DynamicType>(delegate.get())->setParam(std::forward<Arg>(arg)...);
    	}
     
    private:
    	std::unique_ptr<Delegate<R>> delegate;
    };
     
    }
    Il s'agit de l'utilisation de std::remove_reference et de la suppression de quelques const.

    La raison est la suivante, dans l'ensemble des exemples traités, j'utilisais directement un temporaire pour les paramètres. Donc le Arg... valait int, par contre si je décide de créer le paramètre avant sous la forme d'une variable i et de passer ce i à la création de mon FastDelegate je me retrouve avec un Arg... qui vaut int& et donc un std::tuple<int&> ce qui est géant pour avoir le fonctionnement désiré. Il faut donc retirer les références des paramètres du paquet.

    Ensuite pour le std::function stocké, il faut rajouter une référence partout pour pouvoir gérer les situations où la fonction stocké à un référence de les types de ces paramètres.

    On va arriver au problème majeur, tu as donc compris que les types du tuple sont déterminé par les premiers paramètres que tu passes. Si tu passes des paramètres du bon type, aucun problème tout va bien. Mais si tu veux passer autre chose (un placeholder, un reference_wrapper) ca ne va pas aller.

    Il faut donc déduire de l'ensemble des paramètres passé à la création le type réel des paramètres, si c'est un reference_wrapper créé par std::ref ca ne doit pas être problématique de récupérer le type qui va bien, par contre dans le cas des placeholder, ils ne contiennent aucun information sur le type qui va bien, c'est génant.

    Puis il faut aussi remplacer les types du paquet de paramètre par quelque chose qui puisse accepter une valeur, une reference_wrapper et un placeholder.

  8. #68
    Invité
    Invité(e)
    Par défaut
    Ce qui est gênant comme tu dis c'est qu'il ne peux pas me déduire le type des arguments du tuple, par exemple, je dois faire ça si je veux passer un pointeur de fonction avec des arguments qui sont des pointeurs ou bien des références :

    Code cpp : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    odfaeg::OTextArchive oa(ofs);
    void(C::*func)(odfaeg::OTextArchive*) = &C::vtserialize;
    test::FastDelegate<void>(func, new C(), &oa);

    Ce qui bien sûr est assez salle comme solution et pas très pratique, lors de ma toute 1ère solution (tu sais, celle avec mon wrapper fait maison!), il me déduisait automatiquement le type des arguments pour les pointeurs et les simples valeur. (Mais pas pour les références et c'est là que j'aurai pu essayer de faire un wrapper pour le tuple)

    J'ai essayer d'introduire ce code dans le constructeur du delegate mais ça ne fonctionne pas :

    http://coliru.stacked-crooked.com/a/08888a1cd627be05

    Bref c'est bien embêtant.
    L'argument du pointeur sur la fonction est template donc je suis dans le même cas que si c'était un placeholder. (Il ne peut pas me déduire le type quoi)
    Je pense que le language, manque cruellement d'un système de réflexion pour faire ce genre de chose.

    PS : ton code ne compile pas chez moi.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    ||=== Build: Debug in ODFAEG-DEMO (compiler: GNU GCC Compiler) ===|
    /usr/include/c++/4.9/functional||In instantiation of ‘_Res std::_Mem_fn<_Res (_Class::*)(_ArgTypes ...)>::_M_call(_Tp&&, const volatile void*, _Args&& ...) const [with _Tp = B*&; _Args = {}; _Res = void; _Class = C; _ArgTypes = {}]’:|
    /usr/include/c++/4.9/functional|578|required from ‘_Res std::_Mem_fn<_Res (_Class::*)(_ArgTypes ...)>::operator()(_Tp&&, _Args&& ...) const [with _Tp = B*&; _Args = {}; _Req = void; _Res = void; _Class = C; _ArgTypes = {}]’|
    /usr/include/c++/4.9/functional|2126|required from ‘static void std::_Function_handler<void(_ArgTypes ...), _Member _Class::*>::_M_invoke(const std::_Any_data&, _ArgTypes ...) [with _Class = C; _Member = void(); _ArgTypes = {B*&}]’|
    /usr/include/c++/4.9/functional|2427|required from ‘std::function<_Res(_ArgTypes ...)>::function(_Functor) [with _Functor = void (C::*)(); <template-parameter-2-2> = void; _Res = void; _ArgTypes = {B*&}]’|
    /home/laurent/Développement/Projets-c++/ODFAEG-DEMO/delegate.h|24|required from ‘test::FastDelegateImpl<R, ArgT>::FastDelegateImpl(F&&, ArgU&& ...) [with F = void (C::*)(); ArgU = {B*&}; R = void; ArgT = {B*}]’|
    /usr/include/c++/4.9/bits/unique_ptr.h|762|required from ‘typename std::_MakeUniq<_Tp>::__single_object std::make_unique(_Args&& ...) [with _Tp = test::FastDelegateImpl<void, B*>; _Args = {void (C::*)(), B*&}; typename std::_MakeUniq<_Tp>::__single_object = std::unique_ptr<test::FastDelegateImpl<void, B*>, std::default_delete<test::FastDelegateImpl<void, B*> > >]’|
    /home/laurent/Développement/Projets-c++/ODFAEG-DEMO/delegate.h|49|required from ‘test::FastDelegate<R>::FastDelegate(F&&, Arg&& ...) [with F = void (C::*)(); Arg = {B*&}; R = void]’|
    /home/laurent/Développement/Projets-c++/ODFAEG-DEMO/main.cpp|90|required from here|
    /usr/include/c++/4.9/functional|526|error: pointer to member type ‘void (C::)()’ incompatible with object type ‘B’|
    /usr/include/c++/4.9/functional|526|error: return-statement with a value, in function returning 'void' [-fpermissive]|
    ||=== Build failed: 2 error(s), 8 warning(s) (0 minute(s), 1 second(s)) ===|

  9. #69
    En attente de confirmation mail

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2004
    Messages
    1 391
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France, Doubs (Franche Comté)

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

    Informations forums :
    Inscription : Août 2004
    Messages : 1 391
    Points : 3 311
    Points
    3 311
    Par défaut
    Il marche très bien avec :
    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
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
     
    #include<iostream>
    #include<string>
     
    using namespace std::literals;
     
    void foo(int& i)
    { std::cout << i; }
     
    struct A {
    	void foo(int i)
    	{ std::cout << i; }
    };
     
    struct D {
    	void operator()(int i) const
    	{ std::cout << i; }
    };
     
    void bar(const std::string& s)
    { std::cout << s; }
     
    int goo(int i)
    { return i; }
     
    int main(){
    	odfaeg::FastDelegate<void> f1(foo,1);
    	f1();
    	f1.setParam(2);
    	f1();
    	std::cout << std::endl;
     
    	odfaeg::FastDelegate<void> f2(
    		[](int i){ std::cout << i; },
    		3
    	);
    	f2();
    	f2.setParam(4);
    	f2();
    	std::cout << std::endl;
     
    	int i = 5;
    	odfaeg::FastDelegate<void> f3(
    		[i](int j){ std::cout << i << j; },
    		6
    	);
    	f3();
    	f3.setParam(7);
    	f3();
    	std::cout << std::endl;
     
    	A a;
    	odfaeg::FastDelegate<void> f4(&A::foo,&a,8);
    	f4();
    	f4.setParam(&a,9);
    	f4();
    	std::cout << std::endl;
     
    	odfaeg::FastDelegate<void> f5 = f1;
    	f5();
    	f5=f2;
    	f5();
    	std::cout << std::endl;
     
    	odfaeg::FastDelegate<void> f6(D(),10);
    	f6();
    	f6.setParam(11);
    	f6();
    	std::cout << std::endl;
     
    	odfaeg::FastDelegate<void> f7(bar,"ab"s);
    	f7();
    	f7.setParam("abc"s);
    	f7();
    	std::cout << std::endl;
     
    	odfaeg::FastDelegate<int> f8(goo,12);
    	std::cout << f8();
    	f8.setParam(13);
    	std::cout << f8();
    	std::cout << std::endl;
    }
    Bien sur que si il te déduit les types, c'est absolument pas le problème ni ce que j'ai dit dans mon message précédent. Le problème est que ce qu'il déduit ne correspond pas à ce qu'il faut stocker et ça sera exactement pareil avec ton ancien code à partir du moment où tu envisages de traiter tout les foncteurs qui existe.

  10. #70
    En attente de confirmation mail

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2004
    Messages
    1 391
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France, Doubs (Franche Comté)

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

    Informations forums :
    Inscription : Août 2004
    Messages : 1 391
    Points : 3 311
    Points
    3 311
    Par défaut
    Premier jet pour la prise en charge des std::reference_wrapper :
    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
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
     
    namespace odfaeg {
     
    template<class T>
    struct IRefVal {
    	IRefVal()=default;
    	virtual T& get() =0;
    	virtual std::unique_ptr<IRefVal> clone() const = 0;
    	virtual ~IRefVal(){}
     
    protected:
    	IRefVal(const IRefVal&){}
    	IRefVal& operator=(const IRefVal&)
    	{ return *this; }
    };
     
    template<class T>
    struct Ref : IRefVal<T> {
    	Ref(const std::reference_wrapper<T>& r)
    		: ref(r)
    	{}
    	T& get()
    	{ return ref.get(); }
    	std::unique_ptr<IRefVal<T>> clone() const
    	{ return std::make_unique<Ref>(*this); }
     
    private:
    	std::reference_wrapper<T> ref;
    };
     
    template<class T>
    struct Val : IRefVal<T> {
    	Val(const T& t)
    		: val(t)
    	{}
    	T& get()
    	{ return val; }
    	std::unique_ptr<IRefVal<T>> clone() const
    	{ return std::make_unique<Val>(*this); }
     
    private:
    	T val;
    };
     
    template<class T>
    struct RefVal {
    	RefVal(const T& t)
    		: rv(std::make_unique<Val<T>>(t))
    	{}
    	RefVal(const std::reference_wrapper<T>& r)
    		: rv(std::make_unique<Ref<T>>(r))
    	{}
    	RefVal(const RefVal& rhs)
    		: rv(rhs.rv->clone())
    	{}
    	RefVal& operator=(const RefVal& rhs)
    	{ rv=rhs.rv->clone(); return *this; }
    	T& get() const
    	{ return rv->get(); }
     
    private:
    	std::unique_ptr<IRefVal<T>> rv;
    };
     
    template<class T>
    struct ToStoreImpl
    { using type = T; };
     
    template<class T>
    struct ToStoreImpl<std::reference_wrapper<T>>
    { using type = T; };
     
    template<class T>
    struct ToStore
    	: ToStoreImpl<std::remove_reference_t<T>>
    {};
     
    template<class T>
    using ToStore_t = typename
    	ToStore<T>::type;
     
    template<class R>
    struct Delegate {
    	Delegate() =default;
    	virtual std::unique_ptr<Delegate> clone() const = 0;
    	virtual R operator()() = 0;
    	virtual ~Delegate(){}
     
    protected:
    	Delegate(const Delegate&){}
    	Delegate& operator=(const Delegate&)
    	{ return *this; }
    };
     
    template<class R, class... ArgT>
    struct FastDelegateImpl : Delegate<R> {
    	template<class F, class... ArgU>
    	FastDelegateImpl(F&& f, ArgU&&... arg)
    		: func(std::forward<F>(f))
    		, param(std::forward<ArgU>(arg)...)
    	{}
    	std::unique_ptr<Delegate<R>> clone() const
    	{ return std::make_unique<FastDelegateImpl>(*this); }
    	R operator()()
    	{ return call(std::make_index_sequence<sizeof...(ArgT)>()); }
    	template<class... ArgU>
    	void setParam(ArgU&&... arg)
    	{ param=std::make_tuple(std::forward<ArgU>(arg)...); }
     
    private:
    	template<std::size_t... I>
    	R call(std::index_sequence<I...>)
    	{ return func(std::get<I>(param).get()...); }
     
    	std::function<R(ArgT&...)> func;
    	std::tuple<RefVal<ArgT>...> param;
    };
     
    template<class R>
    struct FastDelegate {
    	template<class F, class... Arg>
    	FastDelegate(F&& f, Arg&&... arg) :
    		delegate(std::make_unique
    			<FastDelegateImpl<R,ToStore_t<Arg>...>>
    			(std::forward<F>(f),std::forward<Arg>(arg)...)
    		)
    	{}
    	FastDelegate(FastDelegate& rhs)
    		: delegate(rhs.delegate->clone())
    	{}
    	FastDelegate(const FastDelegate& rhs)
    		: delegate(rhs.delegate->clone())
    	{}
    	FastDelegate(FastDelegate&& rhs) =default;
    	FastDelegate& operator=(const FastDelegate& rhs)
    	{ return operator=(FastDelegate(rhs)); }
    	FastDelegate& operator=(FastDelegate&&) =default;
    	R operator()() const
    	{ return (*delegate)(); }
    	template<class... Arg>
    	void setParam(Arg&&... arg)
    	{
    		using DynamicType =
    			FastDelegateImpl<R,ToStore_t<Arg>...>*;
     
    		if(dynamic_cast<DynamicType>(delegate.get()))
    			dynamic_cast<DynamicType>(delegate.get())->setParam(std::forward<Arg>(arg)...);
    	}
     
    private:
    	std::unique_ptr<Delegate<R>> delegate;
    };
     
    }
    Utilisation :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    	int i(1);
    	odfaeg::FastDelegate<void> f1(foo,std::ref(i));
    	f1();
    	i=2;
    	f1();
    Maintenant le but c'est de faire la même chose en prenant un compte des placeholders, ce qui va être un peu plus compliqué.

  11. #71
    Invité
    Invité(e)
    Par défaut
    Je palais de ce cas-ci :

    Code cpp : 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
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
     
    #include<iostream>
    #include<fstream>
    #include<string>
    #include "delegate.h"
    #include "odfaeg/Core/archive.h"
    using namespace std::literals;
     
    void foo(int i, int j)
    { std::cout << i << j; }
     
    struct A {
    	void foo(int i)
    	{ std::cout << i; }
    };
     
    struct B {
    	virtual void foo()
    	{ std::cout << 1; }
    	template <typename A>
        void vtserialize(A * ar) {
            std::cout<<"serialize base";
        }
    	virtual ~B();
    };
     
    B::~B(){}
     
    struct C : B {
        void foo();
        template <typename A>
        void vtserialize(A * ar) {
            std::cout<<"serialize derived";
        }
    };
     
    void C::foo(){ std::cout << 2; }
    struct D {
    	void operator()(int i) const
    	{ std::cout << i; }
    };
     
    void bar(const std::string& s)
    { std::cout << s; }
     
    int goo(int i)
    { return i; }
     
    int main(){
    	test::FastDelegate<void> f1(foo,3,4);
    	f1();
    	f1.setParams(5,6);
    	f1();
    	std::cout << std::endl;
     
    	test::FastDelegate<void> f2(
    		[](int i, int j){ std::cout << i << j; },
    		7,8
    	);
    	f2();
    	f2.setParams(9,10);
    	f2();
    	std::cout << std::endl;
     
    	int i = 11;
    	test::FastDelegate<void> f3(
    		[i](int j){ std::cout << i << j; },
    		12
    	);
    	f3();
    	f3.setParams(13);
    	f3();
    	std::cout << std::endl;
     
    	A a;
    	test::FastDelegate<void> f4(&A::foo,&a,14);
    	f4();
    	f4.setParams(&a,15);
    	f4();
    	std::cout << std::endl;
     
    	test::FastDelegate<void> f5 = f1;
    	f5();
    	f5=f3;
    	f5();
    	std::cout << std::endl;
     
        C c;
    	B* b = &c;
    	test::FastDelegate<void> f6(&C::foo,&c);
    	f6();
    	f6.setParams(&c);
    	f6();
    	std::cout << std::endl;
     
    	test::FastDelegate<void> f7(D(),16);
    	f7();
    	f7.setParams(17);
    	f7();
    	std::cout << std::endl;
     
    	test::FastDelegate<void> f8(bar,"ab"s);
    	f8();
    	f8.setParams("abc"s);
    	f8();
    	std::cout << std::endl;
     
    	test::FastDelegate<void> f9(bar,"de"s);
    	f9();
    	f9.setParams("def"s);
    	f9();
    	std::cout << std::endl;
     
    	test::FastDelegate<int> f10(goo,18);
    	std::cout << f10();
    	f10.setParams(19);
    	std::cout << f10();
    	std::cout << std::endl;
    	std::ofstream ofs("FichierDeSerialisation");
    	odfaeg::OTextArchive oa(ofs);
    	test::FastDelegate<void>(&C::vtserialize, new C(), &oa);

    Avec ton système de wrapper sur un std::function, comment veut tu qu'il me déduise si le paramètre de la fonction template vtserialize est de type OTextArchive, OTextArchive& ou bien OTextArchive* ?

    Bref ça me met une overload function error avec ton code c'est à dire celui ou tu utilise std::function. (avec le mien ça passe sans problème si je rajoute la prise en charge du wrapper pour les références)

    Tandis que le std::function ne me déduis pas si le pointeur de fonction à un argument de type OTextArchive ou bien OTextArchive*. (Il fait pas la différence entre les deux contrairement à une surcharge normale c'est à dire une surcharge sans le std::function)

    Je pense que le problème vient carrément du forwarding qui converti tout en référence ou bien alors dois je faire un wrapper pour les pointeurs également ?

  12. #72
    En attente de confirmation mail

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2004
    Messages
    1 391
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France, Doubs (Franche Comté)

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

    Informations forums :
    Inscription : Août 2004
    Messages : 1 391
    Points : 3 311
    Points
    3 311
    Par défaut
    Oui, mais ce cas là est pris en compte par DynamicWrapper, or dans le dernier code que j'ai posté je n'ai pas pris la peine de le mettre, à toi de le rajouter.

    Non le forwarding ne pose aucun problème. J'ai juste viré le DynamicWrapper et donc la gestion de ce cas pour me concentrer sur std::reference_wrapper et les placeholder qui sont bien plus important (que j'ai traité dans mon dernier message que tu sembles avoir ignoré).

  13. #73
    Invité
    Invité(e)
    Par défaut
    Bah déjà le dynamic cast c'est à l'appel de setParam que je le fait, pas au moment de la création du delegate donc ça :

    Code cpp : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    C c;
    	B* b = &c;
    	test::FastDelegate<void> f6(&C::foo,b);
    	f6();
    	f6.setParams(&c);
    	f6();

    C'est pas bon c'est plutôt ça dont j'ai besoin :

    Code cpp : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    C c;
    	B* b = &c;
    	test::FastDelegate<void> f6(&C::foo,&c);
    	f6();
    	f6.setParams(b);
    	f6();

    Ainsi si lors de l'appel à setParam je ne connais pas le type dynamique de b, je peux faire un dynamic cast et appeler le pointeur de fonction sur le type dynamique de b dans le delegate.


    Les placeholders et les références sont en effet, plus important.

  14. #74
    En attente de confirmation mail

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2004
    Messages
    1 391
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France, Doubs (Franche Comté)

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

    Informations forums :
    Inscription : Août 2004
    Messages : 1 391
    Points : 3 311
    Points
    3 311
    Par défaut
    J'estime avoir été patient jusque là, alors soit tu te concentres sur les situations importantes en oubliant tes situations d'intérêt plus que limité (un dynamic_cast automatique c'est très limite, une fonction template présente dans la classe mère et la classe fille c'est assez dangereux, ton code d'origine a plein de fuite mémoire et d'UB qui se passent de commentaire) soit j'arrête simplement de poster des propositions (pas parfaites mais bien mieux que ton code d'origine j'en suis convaincu).

    Si ton message suivant ne contient pas une proposition pour régler la question des placeholders ou une question sur une de mes propositions présendante, je ne ferais pas de réponse (si ce n'ai pour poster un code brut sans commentaire, utilisant boost et sans exemple d'utilisation, mais répondant à l'ensemble de la problématique, du moins si j'ai l'envie de résoudre la question).

  15. #75
    Invité
    Invité(e)
    Par défaut
    Je crois qu'on s'est mal compris, je vois parfaitement ou tu veux en venir avec tes codes, et, je pense pouvoir les adapter facilement avec ma situation, et, j'avoue qu'ils sont meilleur que les miens.

    Simuler un appel de fonction virtuel template est peut être dangereux (enfin, avec mon code je n'ai pas de soucis et il s'exécute bien à part que je dois l'améliorer pour les fuites de mémoire et les UB, car, lorsque j'ai commencé à rédigé ce code le c++14 n'existait pas encore, et je ne voulais pas dépendre de boost, je voulais attendre que le c++14 sorte.)

    Si j'ai posté c'est uniquement parce que je suis assez newbie en c++11 et c++14 comme tu peux le remarquer et que j'avais quelque questions à propos de ce langage et plus particulièrement au sujet des fonctions anonymes.

    Donc, tu peux abandonner ces deux cas là (celui de la fonction dynamique et celui des fonctions templates dans la classe de base et la classe dérivée que, de toute façon, je n'ai pas de problème avec ce code) et te concentrer sur le système de placeholders.

    Je pense avoir compris que contrairement à d'autres language qui utilisent un système de réflexion qu'il est dangereux de faire certaines choses en c++.

    Justement, en parlant de placeholders, je pensais partir sur du SFINAE. (Et je pense que tu pourrais facilement te passer d'un wrapper )

    Code cpp : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    template <typename F, typename A>
    FastDelegate(F&& func, A&& args) {
     
    }
    template <typename F, typename A, class = typename std::enable_if<std::is_placeholder<A...>::value>::type>
    FastDelegate(F&& func, A&& args) {
     
    }
    template <typename F, typename A, class = typename std::enable_if<std::is_reference<A...>::value>::type>
    FastDelegate(F&& func, A&& args) {
     
    }

    J'ai pas encore terminé de rédigé le code mais bon..., je pense que j'ai enfin une piste.

    Finalement la prise en charge avec le dynamic wrapper n'était pas si compliquée :

    Code cpp : 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
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
     
    #ifndef ODFAEG_FAST_DELEGATE_HPP
    #define ODFAEG_FAST_DELEGATE_HPP
    #include<functional>
    #include<memory>
    #include<tuple>
    #include<type_traits>
    #include<utility>
     
    namespace test {
    template<class T>
    struct IRefVal {
    	IRefVal()=default;
    	virtual T& get() =0;
    	virtual std::unique_ptr<IRefVal> clone() const = 0;
    	virtual ~IRefVal(){}
     
    protected:
    	IRefVal(const IRefVal&){}
    	IRefVal& operator=(const IRefVal&)
    	{ return *this; }
    };
     
    template<class T>
    struct Ref : IRefVal<T> {
    	Ref(const std::reference_wrapper<T>& r)
    		: ref(r)
    	{}
    	T& get()
    	{ return ref.get(); }
    	std::unique_ptr<IRefVal<T>> clone() const
    	{ return std::make_unique<Ref>(*this); }
     
    private:
    	std::reference_wrapper<T> ref;
    };
     
    template<class T>
    struct Val : IRefVal<T> {
    	Val(const T& t)
    		: val(t)
    	{}
    	T& get()
    	{ return val; }
    	std::unique_ptr<IRefVal<T>> clone() const
    	{ return std::make_unique<Val>(*this); }
     
    private:
    	T val;
    };
     
    template<class T>
    struct RefVal {
    	RefVal(const T& t)
    		: rv(std::make_unique<Val<T>>(t))
    	{}
    	RefVal(const std::reference_wrapper<T>& r)
    		: rv(std::make_unique<Ref<T>>(r))
    	{}
    	RefVal(const RefVal& rhs)
    		: rv(rhs.rv->clone())
    	{}
    	RefVal& operator=(const RefVal& rhs)
    	{ rv=rhs.rv->clone(); return *this; }
    	T& get() const
    	{ return rv->get(); }
     
    private:
    	std::unique_ptr<IRefVal<T>> rv;
    };
     
    template<class T>
    struct ToStoreImpl
    { using type = T; };
     
    template<class T>
    struct ToStoreImpl<std::reference_wrapper<T>>
    { using type = T; };
     
    template<class T>
    struct ToStore
    	: ToStoreImpl<std::remove_reference_t<T>>
    {};
     
    template<class T>
    using ToStore_t = typename
    	ToStore<T>::type;
     
    template<class R, class C, class... ArgT>
    struct DynamicWrapper {
    	DynamicWrapper(R(C::*pf)(ArgT...)) : pfunc(pf){}
    	template<class O, class... ArgU>
    	R operator()(O* o, ArgU&&... arg) const
    	{
    		if(dynamic_cast<C*>(o))
    			return (dynamic_cast<C*>(o)->*pfunc)(std::forward<ArgU>(arg)...);
    	}
    private:
    	R (C::*pfunc)(ArgT...);
    };
    template<class F>
    class DynamicFunction;
     
    template<class R, class... ArgT>
    class DynamicFunction<R(ArgT...)>
    	: std::function<R(ArgT...)>
    {
    	using Base = std::function<R(ArgT...)>;
     
    public:
    	template<class F>
    	DynamicFunction(F&& f) : Base(std::forward<F>(f))
    	{}
    	template<class C, class... ArgU>
    	DynamicFunction(R (C::*pf)(ArgU...))
    		: Base(DynamicWrapper<R,C,ArgU...>(pf))
    	{}
     
    	using Base::operator();
    };
    template <typename R>
    struct Delegate {
    	Delegate() =default;
    	virtual std::unique_ptr<Delegate> clone() const = 0;
    	virtual R operator()() const = 0;
    	virtual ~Delegate();
    protected:
    	Delegate(const Delegate&){}
    	Delegate& operator=(const Delegate&)
    	{ return *this; }
    };
    template <typename R>
    Delegate<R>::~Delegate(){}
    template<class R, class... ArgT>
    struct FastDelegateImpl : Delegate<R> {
    	template<class F, class... ArgU>
    	FastDelegateImpl(F&& f, ArgU&&... arg)
    		: func(std::forward<F>(f))
    		, param(std::forward<ArgU>(arg)...)
    	{}
    	std::unique_ptr<Delegate<R>> clone() const
    	{ return std::make_unique<FastDelegateImpl>(*this); }
    	R operator()() const
    	{ return call(std::make_index_sequence<sizeof...(ArgT)>()); }
    	template<class... ArgU>
    	void setParam(ArgU&&... arg)
    	{ param=std::make_tuple(std::forward<ArgU>(arg)...); }
     
    private:
    	template<std::size_t... I>
    	R call(std::index_sequence<I...>) const
    	{ return func(std::get<I>(param).get()...); }
    	DynamicFunction<R(ArgT...)> func;
    	std::tuple<RefVal<ArgT>...> param;
    };
    template <typename R>
    struct FastDelegate {
    	template<class F, class... Arg>
    	FastDelegate(F&& f, Arg&&... arg) :
    		delegate(std::make_unique<FastDelegateImpl<R, ToStore_t<Arg>...>>
    			(std::forward<F>(f),std::forward<Arg>(arg)...)
    		)
    	{}
    	FastDelegate(FastDelegate& rhs) : delegate(rhs.delegate->clone())
    	{}
    	FastDelegate(const FastDelegate& rhs) : delegate(rhs.delegate->clone())
    	{}
    	FastDelegate(FastDelegate&& rhs) =default;
    	FastDelegate& operator=(const FastDelegate& rhs)
    	{ return operator=(FastDelegate(rhs)); }
    	FastDelegate& operator=(FastDelegate&&) =default;
    	R operator()() const
    	{ (*delegate)(); }
    	template<class... Arg>
    	void setParam(Arg&&... arg)
    	{
    		using DynamicType = FastDelegateImpl<R, ToStore_t<Arg>...>*;
     
    		if(dynamic_cast<DynamicType>(delegate.get()))
    			dynamic_cast<DynamicType>(delegate.get())->setParam(std::forward<Arg>(arg)...);
    	}
    	void boo(){}
     
    private:
    	std::unique_ptr<Delegate<R>> delegate;
    };
    }
    #endif // PLACE_HOLDERS_H

    Il reste plus que le cas avec les placeholders à gérer donc... (le plus difficile)
    Dernière modification par Invité ; 07/09/2014 à 08h20.

  16. #76
    Invité
    Invité(e)
    Par défaut
    C'est bien ce que je pensais, pas besoin d'un fonction template, même avec les fonctions normales il ne me résous pas les problèmes d'overload : (J'ai juste réuni tes 2 codes précédent. (celui avec référence et celui sans référence)
    Le code du delegate est identique au dernier code que tu m'as donné. (c'est à dire sans la dynamic function)

    Code cpp : 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
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
     
    #include<iostream>
    #include<string>
    #include <fstream>
    #include "delegate.h"
    using namespace std::literals;
     
    void foo(int i, int j)
    { std::cout << i << j; }
     
    struct A {
    	void foo(int i)
    	{ std::cout << i; }
    };
     
    struct B {
    	virtual void foo()
    	{ std::cout << 1; }
    	virtual ~B();
    };
     
    B::~B(){}
     
    struct C : B { void foo(); };
     
    void C::foo(){ std::cout << 2; }
     
    struct D {
    	void operator()(int i) const
    	{ std::cout << i; }
    };
     
    void bar(const std::string& s)
    { std::cout << s; }
     
    int goo(int i)
    { return i; }
    void foo (int &ri) {  std::cout<<ri; }
    int main(){
    	test::FastDelegate<void> f1(foo,3,4);
    	f1();
    	f1.setParam(5,6);
    	f1();
    	std::cout << std::endl;
     
    	test::FastDelegate<void> f2(
    		[](int i, int j){ std::cout << i << j; },
    		7,8
    	);
    	f2();
    	f2.setParam(9,10);
    	f2();
    	std::cout << std::endl;
     
    	int i = 11;
    	test::FastDelegate<void> f3(
    		[i](int j){ std::cout << i << j; },
    		12
    	);
    	f3();
    	f3.setParam(13);
    	f3();
    	std::cout << std::endl;
     
    	A a;
    	test::FastDelegate<void> f4(&A::foo,&a,14);
    	f4();
    	f4.setParam(&a,15);
    	f4();
    	std::cout << std::endl;
     
    	test::FastDelegate<void> f5 = f1;
    	f5();
    	f5=f3;
    	f5();
    	std::cout << std::endl;
     
    	C c;
    	B* b = &c;
    	test::FastDelegate<void> f6(&C::foo,&c);
    	f6();
    	f6.setParam(b);
    	f6();
    	std::cout << std::endl;
     
    	test::FastDelegate<void> f7(D(),16);
    	f7();
    	f7.setParam(17);
    	f7();
    	std::cout << std::endl;
     
    	test::FastDelegate<void> f8(bar,"ab"s);
    	f8();
    	f8.setParam("abc"s);
    	f8();
    	std::cout << std::endl;*/
        int i(1);
    	test::FastDelegate<void> f9(foo,std::ref(i));
    	f9();
    	i=2;
    	f9();
    	test::FastDelegate<int> f10(goo,18);
    	std::cout << f10();
    	f10.setParam(19);
    	std::cout << f10();
    	std::cout << std::endl;
    }

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    /home/laurent/Développement/Projets-c++/ODFAEG-DEMO/main.cpp|39|error: no matching function for call to ‘test::FastDelegate<void>::FastDelegate(<unresolved overloaded function type>, int, int)’|
    Je pense qu'il faut partir sur du SFINAE.

  17. #77
    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
    Bon, ça commence à faire un sacré bail que tu nous demande de l'aide sur ton projet.

    On pourrait avoir accès à une spécification, un cahier des charges ou un cas d'usage nominal?
    Histoire de comprendre non pas ce que tu veux faire techniquement mais le problème que ton programme résout?

    Tu sembles complètement aveuglé par le moyen, perdant de vue que tu as un objectif.
    Objectif qui se doit d'être défini, fini et surtout délimité pour être atteignable.
    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

  18. #78
    Invité
    Invité(e)
    Par défaut
    Salut,

    Pour moi mon objectif est atteint, enfin, le reste c'est de la simplification de code ou bien de l'ajout de fonctionnalité comme par exemple :

    -Le support des std::ref.
    -Le support des placeholders.

    Pour l'instant mon delegate ne supporte que les pointeurs de fonctions qui prenne des valeurs ou bien des pointeurs en argument.

    Au niveau utilisation cela donnerais quelque chose comme :

    Code cpp : 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
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
     
    #include<iostream>
    #include<string>
    #include <fstream>
    #include "delegate.h"
    using namespace std::literals;
     
    void foo(int i, int j)
    { std::cout << i << j; }
     
    struct A {
    	void foo(int i)
    	{ std::cout << i; }
    };
     
    struct B {
    	virtual void foo()
    	{ std::cout << 1; }
    	virtual ~B();
    };
     
    B::~B(){}
     
    struct C : B { void foo(); };
     
    void C::foo(){ std::cout << 2; }
     
    struct D {
    	void operator()(int i) const
    	{ std::cout << i; }
    };
     
    void bar(const std::string& s)
    { std::cout << s; }
     
    int goo(int i)
    { return i; }
    void foo (int &ri) {  std::cout<<ri; }
    int main(){       
    	test::FastDelegate<void> f1(foo,3,4);
    	f1();
    	f1.setParams(5,6);
    	f1();
    	std::cout << std::endl;     
    	test::FastDelegate<void> f2(
    		[](int i, int j){ std::cout << i << j; },
    		7,8
    	);
    	f2();
    	f2.setParams(9,10);
    	f2();
    	std::cout << std::endl;      
    	int i = 11;
    	test::FastDelegate<void> f3(
    		[i](int j){ std::cout << i << j; },
    		12
    	);
    	f3();
    	f3.setParams(13);
    	f3();
    	std::cout << std::endl;      
    	A a;
    	test::FastDelegate<void> f4(&A::foo,&a,14);
    	f4();
    	f4.setParams(&a,15);
    	f4();
    	std::cout << std::endl;
     
    	test::FastDelegate<void> f5 = f1;
    	f5();
    	f5=f3;
    	f5();
    	std::cout << std::endl;
     
    	C c;
    	B* b = &c;
    	test::FastDelegate<void> f6(&C::foo,&c);
    	f6();
    	f6.setParams(b);
    	f6();
    	std::cout << std::endl;
     
    	test::FastDelegate<void> f7(D(),16);
    	f7();
    	f7.setParams(17);
    	f7();
    	std::cout << std::endl;
     
    	test::FastDelegate<void> f8(bar,"ab"s);
    	f8();
    	f8.setParams("abc"s);
    	f8();
    	std::cout << std::endl;
        int vi(1);
       	test::FastDelegate<void> f9(f, std::ref(v1));
    	f9();	
    	vi=2;
    	f9();	
    	test::FastDelegate<int> f10(goo,18);
    	std::cout << f10();
    	f10.setParams(19);
    	std::cout << f10();
    	std::cout << std::endl;
            test::FastDelegate<void> f11(goo, _1)
            f11.setParams(20);
            f11();
            std::cout<<std::endl;
    }

    Le but final est donc d'uniformiser tous les types de fonction avec le même type de retour avec gestion du passage par valeur, par référence ou par pointeur ainsi que des placeholders.
    Le delegate se charge de la déduction des types des paramètres de la fonction en fonction des valeurs des arguments de la fonction que je passe au delegate. (A vrai dire c'est ça qui fait la force du delegate)

    Personnellement je ne sais pas si j'y arriverai et si il y a moyen de le faire en c++. (surtout la version utilisant les placeholders, vu que je vois que std::bind utilise un type non spécifié et donc non stockable dans un conteneur.)
    C'est pour ça que j'ai créer se sujet, il est vrai que mon code est fort brut (mais il fonctionne pour ce que je veux faire à condition que je passe les valeurs par pointeurs à mes fonctions), c'est d'ailleurs pour ça que flob90 m'a proposé une autre version.

    J'utilise ensuite un listener pour connecter les fonctions entre elle, c'est exactement le même principe que le système de signaux et de slots de QT. (Mais avec en plus le support des lambdas expressions)
    J'utilise aussi également une factory, pour appeler des fonctions membre template en fonction du type dynamique de l'objet à l'exécution vu que les fonctions template ne peuvent pas être virtuelles, c'est expliqué sur mon devblog : (Le principe est très similaire à celui utilisé par boost et son système de serialization)

    http://lolilolightdevblog.wordpress.com/

    Donc l'objectif est atteint mais apparemment d'après flob90 il y a moyen de faire mieux.

    Je ne sais pas si son code sera plus pratique que le mien à l'utilisation, en tout cas j'ai rencontré quelque problèmes avec son code :

    -J'ai un crash en enregistrant les delegates dans la factory lorsque ceux-ci utilisent std::function. (Donc je n'ai pas utilisé std::function mais fais mon propre wrapper)
    -J'ai des erreur d'overload ce qui m'oblige à déclarer et à affecter à chaque fois un pointeur de fonction avant de le passer au delegate. (Pas très pratique)

    Hors que avec mon code j'ai juste une erreur d'overload lorsque je passe un pointeur de fonction prenant des références en argument. (Et il ne gère pas std::reference_wrapper)

    Bref moi j'essaye juste d'expliquer ce que je veux, maintenant, le reste, ça, je ne peux malheureusement pas aider. (et surtout pas avec le c++14 et std::function qui me font pédaler dans la choucroute mais de manière totale comme vous avez pu le remarquer)

  19. #79
    Invité
    Invité(e)
    Par défaut Ne cherchez plus !
    Ne cherchez plus!

    Je pense que je vais faire mon choix et garder ma solution initiale avant qu'il y en ai qui commence à perdre patience (et moi aussi je commence à perdre patience) et après avoir essayé plusieurs codes, c'est celle qui finalement me convient le mieux :

    -Elle gère le dynamic_cast au cas ou je ne connais pas le type dynamique de l'objet lors de l'appel à setParam. (Ce qui est le cas ici)
    -Elle force le passage d'argument par pointeur ou bien par valeur ce qui ne pose pas de problèmes lors de la résolution d'overload contrairement aux références :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    void f(int)
    void f(int&)
    int i = 2;
    delegate(f, std::ref(2));
    Ou le compilateur ne peux pas savoir quel type de pointeur de fonction stocker (f(int) ou bien f(int&) ? )

    Hors que dans ce cas là, c'est clair :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    void f(int)
    void f(int*)
    int i = 2;
    delegate(f, &i);
    Il va d'office choisir f(int*). (Enfin tout du moins, si je ne réutilise pas std::function dans mon delegate mais bel et bien mon code initial avec mon wrapper fait maison, car si j'utilise std::function dans le delegate il ne parvient pas non plus à résoudre l'ambiguité donc je dois le faire explicitement ce que je voudrais éviter, car, ma factory utilise une macro, il faut donc que le compilateur puisse me déduire implicitement le type du pointeur sur ma fonction lors du passage du pointeur de fonction au delegate dans la macro :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    #define REGISTER_FUNC(ID, funcName, FID, BASE, TYPE, args...) \
    { \
    REGISTER_TYPE(ID, BASE, TYPE) \
    odfaeg::FastDelegate<void> delegate##ID##funcName##FID (&TYPE::vt##funcName, args); \
    odfaeg::BaseFact<BASE>::register_function(typeid(TYPE).name(), #funcName, #FID, delegate##ID##funcName##FID); \
    }
    Le seul inconvénient (qui n'est pas un gros problème) est celui-ci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    template <typename A>
    void vtserialize (A * a) {
          (*a)(//Variables à serialiser)
    }
    je dois écrire ça : (*ar)(blablalba) au lieu de ça ar(blablalbah) ce qui est un peu plus gênant au niveau de la syntaxe mais..., c'est moins gênant que les problèmes que j'ai eu ci-dessus avec le code de flob90.
    Dernière modification par Invité ; 07/09/2014 à 13h35. Motif: Penser aux balises ! Merci

  20. #80
    Invité
    Invité(e)
    Par défaut
    Ha bah c'est bon, ça marche avec std::bind et les placeholders maintenant.

    Code cpp : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    void(*f)(int, int) = &foo;
    odfaeg::FastDelegate<void> f1(std::bind(f,3 , _1), 3, _1);
    f1.setParams(4);
    f1();
    std::cout << std::endl;

    Pas besoin de recréer une système donc, c'est sûrement parce que j'ai changé de version de gcc que ça marche maintenant, avant il ne me déduisait pas le type de F lors de l'appel à setParam mais maintenant il le fait, donc, c'est tout simplement génial!

    Et ma classe FastDelegate peut ainsi tout stocker (sauf les std::reference_wrapper) que je ne vois pas comment gérer ça dans le cadre de pointeurs de fonctions dynamique.
    Mais ça, je peux m'en passer pour le moment, les pointeurs feront l'affaire.

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

Discussions similaires

  1. Réponses: 12
    Dernier message: 13/06/2011, 09h28
  2. Réponses: 0
    Dernier message: 21/02/2011, 15h58
  3. Réponses: 1
    Dernier message: 11/03/2010, 12h01
  4. Quelques questions à propos de DreamShield
    Par kahoerre dans le forum Dreamshield
    Réponses: 10
    Dernier message: 10/06/2009, 09h44
  5. Quelques question à propos des technologies RAID
    Par DranDane dans le forum Composants
    Réponses: 6
    Dernier message: 12/08/2008, 12h40

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