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 :

[Optimisation] Votre avis sur ma bibliothèque Multiple Dispatch


Sujet :

Langage C++

  1. #21
    Membre du Club
    Homme Profil pro
    C++
    Inscrit en
    Janvier 2013
    Messages
    45
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : C++

    Informations forums :
    Inscription : Janvier 2013
    Messages : 45
    Points : 44
    Points
    44
    Par défaut
    Citation Envoyé par Flob90 Voir le message
    Pour l'implémentation, j'ai une petite solution en préparation (un segmentation fault à corriger avant de te la proposer). Mais l'idée est d'arriver à une utilisation du type :
    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
     
    #include<iostream>
     
    struct chat;
    struct chien;
     
    struct animal
    	: dispatch::accept_visitor<animal,chat,chien>
    { };
     
    struct chat
    	: dispatch::acceptable<animal,chat>
    { };
     
    struct chien
    	: dispatch::acceptable<animal,chien>
    { };
     
    struct attaquer : dispatch::dispatchable<animal>
    {
    	using dispatch::dispatchable<animal>::operator();
     
    	void operator()(chat&, chat&) const
    	{ std::cout <<  "griffe - griffe" << std::endl;}
    	void operator()(chat&, chien&) const
    	{ std::cout <<  "griffe - mord  " << std::endl;}
    	void operator()(chien&, chat&) const
    	{ std::cout <<  "mord   - griffe" << std::endl;}
    	void operator()(chien&, chien&) const
    	{ std::cout << "mord   - mord  " << std::endl;}
    };
     
    int main()
    {
    	chat c1;
    	chien c2;
     
    	animal& a1 =c1;
    	animal& a2 =c2;
     
    	attaquer()(a1,a2);
    }
    L'implémentation repose sur une unique classe (et quelques utilitaires) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    template<
    	class To_Visit, class Visited, bool,
    	class Visitor, class Concrete,
    	class Fun
    >
    struct dispatcher
    Ou To_Visit/Visited/Concrete sont des std::tuple.
    C'est super, j'ai hate de voir ça !
    J'avais codé un système similaire à celui que tu proposes il y a quelques temps, c'est intéressant de pouvoir discuter des difficultés qu'on aura rencontrées en chemin et de voir les différentes solutions possibles.

    Citation Envoyé par Flob90 Voir le message
    Pour le SRP, tu considères std::tuple comme un détail d'implémentation, mais si je la considère comme une classe utilitaire, alors je suis couplé à std::tuple de la même manière que tu l'es à CircularBuffer.
    Hum je vois.
    J'aime bien encapsuler la std:: quand je l'utilise pour éviter des problèmes du genre ceux qu'il y a eut lors du passage aux génériques en Java. Robert C. Martin en parle dans Clean Code.

    [EDIT]
    Nouvelle question en rapport : http://www.developpez.net/forums/d14...tion-r-values/

  2. #22
    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
    Alors voila ce que j'ai fait (non commenté, désolé, mais comme c'est basé sur ton idée, tu devrais pas avoir trop de problème pour le lire) :
    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
    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
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
     
    #include<type_traits>
    #include<tuple>
    #include<utility>
     
    namespace dispatch
    {
     
    template<class,class>
    struct acceptable;
     
    template<class Abstract, class... Concrete>
    struct visitor;
     
    template<class Abstract, class Concrete, class... Concrete_Tail>
    struct visitor<Abstract,Concrete,Concrete_Tail...>
    	: visitor<Abstract,Concrete_Tail...>
    {
    	visitor() =default;
    	visitor(const visitor&) =default;
    	visitor& operator=(const visitor&) =default;
    	using visitor<Abstract,Concrete_Tail...>::visit;
    	virtual void visit(acceptable<Abstract,Concrete>&) =0;
     
    protected:
    	~visitor(){}
    };
     
    template<class Abstract, class Concrete>
    struct visitor<Abstract,Concrete>
    {
    	visitor() =default;
    	visitor(const visitor&) =default;
    	visitor& operator=(const visitor&) =default;
    	virtual void visit(acceptable<Abstract,Concrete>&) =0;
     
    protected:
    	virtual ~visitor(){}
    };
     
    template<class,class>
    struct accept_type;
     
    template<
    	class Abstract, class... Concrete,
    	class T
    >
    struct accept_type<visitor<Abstract,Concrete...>,T>
    { using type =acceptable<Abstract,T>; };
     
    template<class>
    struct concrete_type;
     
    template<class Abstract, class... Concrete>
    struct concrete_type<visitor<Abstract,Concrete...>>
    { using type =std::tuple<Concrete...>; };
     
    template<class Abstract, class... Concrete>
    struct accept_visitor
    {
    	using visitor_type =visitor<Abstract,Concrete...>;
     
    	accept_visitor() =default;
    	accept_visitor(const accept_visitor&) =delete;
    	accept_visitor& operator=(const accept_visitor&) =delete;
    	virtual void accept(visitor_type&) =0;
    	virtual ~accept_visitor(){}
    };
     
    template<class Abstract, class Concrete>
    struct acceptable : Abstract
    {
    	void accept(typename Abstract::visitor_type& v)
    	{ v.visit(*this); }
    };
     
    template<
    	class To_Visit, class Visited, bool,
    	class Visitor, class Concrete,
    	class Fun
    >
    struct dispatcher : Visitor
    {
    	dispatcher(const To_Visit& tv,const Visited& v, const Fun& f)
    		: to_visit(tv), visited(v), fun(f)
    	{}
    	dispatcher(const dispatcher&) =default;
    	dispatcher& operator=(const dispatcher&) =default;
    	using Visitor::visit;
     
    protected:
    	~dispatcher(){}
     
    	const To_Visit& to_visit;
    	Visited visited;
    	Fun fun;
    };
     
    template<class Visitor, class To_Visit, class Visited, class Fun>
    auto make_dispatcher(const To_Visit& to_visit, Visited&& visited, Fun&& fun)
    {
    	return dispatcher<
    		To_Visit,Visited,
    		std::tuple_size<To_Visit>::value==std::tuple_size<Visited>::value,
    		Visitor,typename concrete_type<Visitor>::type,
    		Fun
    	>
    	(to_visit,std::forward<Visited>(visited), std::forward<Fun>(fun));
    }
     
    template<
    	class To_Visit, class Visited,
    	class Visitor, class T, class... Concrete,
    	class Fun
    >
    struct dispatcher<
    	To_Visit,Visited,false,
    	Visitor,std::tuple<T,Concrete...>,
    	Fun
    >
    	: dispatcher<
    		To_Visit,Visited,false,
    		Visitor,std::tuple<Concrete...>,
    		Fun
    	>
    {
    private:
    	using base =dispatcher<
    		To_Visit,Visited,false,
    		Visitor,std::tuple<Concrete...>,
    		Fun
    	>;
     
    public:
    	using base::base;
    	dispatcher(const dispatcher&) =default;
    	dispatcher& operator=(const dispatcher&) =default;
    	void operator()()
    	{ std::get<std::tuple_size<Visited>::value>(base::to_visit).accept(*this); }
    	using base::visit;
    	void visit(typename accept_type<Visitor,T>::type& data)
    	{
    		make_dispatcher<Visitor>(
    			base::to_visit,
    			std::tuple_cat<>(
    				base::visited,
    				std::tuple<T&>(static_cast<T&>(data))
    			),
    			base::fun
    		)();
    	}
     
    protected:
    	~dispatcher(){}
    };
     
    template<
    	class To_Visit, class Visited,
    	class Abstract, class T, class... Concrete,
    	class Fun
    >
    struct dispatcher<
    	To_Visit,Visited,false,
    	visitor<Abstract,T,Concrete...>,std::tuple<T,Concrete...>,
    	Fun
    >
    	: dispatcher<
    		To_Visit,Visited,false,
    		visitor<Abstract,T,Concrete...>,std::tuple<Concrete...>,
    		Fun
    	>
    {
    private:
    	using base =dispatcher<
    		To_Visit,Visited,false,
    		visitor<Abstract,T,Concrete...>,std::tuple<Concrete...>,
    		Fun
    	>;
     
    public:
    	using base::base;
    	void operator()()
    	{ std::get<std::tuple_size<Visited>::value>(base::to_visit).accept(*this); }
    	using base::visit;
    	void visit(acceptable<Abstract,T>& data)
    	{
    		make_dispatcher<visitor<Abstract,T,Concrete...>>(
    			base::to_visit,
    			std::tuple_cat<>(
    				base::visited,
    				std::tuple<T&>(static_cast<T&>(data))
    			),
    			base::fun
    		)();
    	}
    };
     
    template<
    	class To_Visit, class Visited,
    	class Visitor, class Concrete,
    	class Fun
    >
    struct dispatcher<
    	To_Visit,Visited,true,
    	Visitor,Concrete,
    	Fun
    >
    {
    	dispatcher(const To_Visit& tv, const Visited& v, const Fun& f)
    		: to_visit(tv), visited(v), fun(f)
    	{}
    	void operator()()
    	{ apply(std::make_index_sequence<std::tuple_size<Visited>::value>()); }
     
    private:
    	template<std::size_t... I>
    	void apply(std::index_sequence<I...>)
    	{ fun(std::get<I>(visited)...); }
     
    	const To_Visit& to_visit;
    	Visited visited;
    	Fun fun;
    };
     
    template<class Fun, class Abstract>
    struct dispatchable
    {
    	dispatchable() =default;
    	dispatchable(const dispatchable&) =default;
    	dispatchable& operator=(const dispatchable&) =default;
    	template<class... Arg>
    	void apply(Arg&&... arg)
    	{
    		auto t =std::forward_as_tuple(std::forward<Arg>(arg)...);
    		make_dispatcher
    			<typename Abstract::visitor_type>
    			(t,std::tuple<>(),*static_cast<Fun*>(this))();
    	}
     
    protected:
    	~dispatchable(){}
    };
     
    }
     
    #include<iostream>
     
    struct chat;
    struct chien;
     
    struct animal
    	: dispatch::accept_visitor<animal,chat,chien>
    { };
     
    struct chat
    	: dispatch::acceptable<animal,chat>
    { };
     
    struct chien
    	: dispatch::acceptable<animal,chien>
    { };
     
    struct attaquer : dispatch::dispatchable<attaquer,animal>
    {
    	void operator()(chat&, chat&) const
    	{ std::cout <<  "griffe - griffe" << std::endl;}
    	void operator()(chat&, chien&) const
    	{ std::cout <<  "griffe - mord  " << std::endl;}
    	void operator()(chien&, chat&) const
    	{ std::cout <<  "mord   - griffe" << std::endl;}
    	void operator()(chien&, chien&) const
    	{ std::cout << "mord   - mord  " << std::endl;}
    };
     
    int main()
    {
    	chat c1;
    	chien c2;
     
    	animal& a1 =c1;
    	animal& a2 =c2;
     
    	attaquer().apply(a1,a1);
    	attaquer().apply(a1,a2);
    	attaquer().apply(a2,a1);
    	attaquer().apply(a2,a2);
    }
    Si il y a des parties que tu ne comprends pas immédiatement, n'hésite pas à demander j'expliquerais.

    C'est pas encore l'idéal (et j'ai clairement pas testé toutes les situations). Il y a des améliorations à faire au niveau du forwarding et probablement de la const-correctness. Idéalement des choses à faire au niveau de test statiques pour rendre les erreurs de compilation lisible (des assertions statiques qui vont bien). Après une fonction libre apply serait pas mal plutôt que de l'avoir en membre (mais c'est du détail).

    Edit: Petite correction pour éviter le slicing.

  3. #23
    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
    Quelques changement, avec quelques commentaires dans le code cette fois :
    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
    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
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
     
    #include<tuple>
    #include<type_traits>
    #include<utility>
     
    namespace dispatch
    {
     
     
    //Utilitaire pour ajouter un type à la fin d'un tuple
    template<class,class>
    struct cat_type;
     
    template<class T, class... Arg>
    struct cat_type<std::tuple<Arg...>,T>
    {
    	using type =std::tuple<Arg...,T>;
    };
     
     
    //Classe qui surcharge accept pour les types concret
    template<class Abstract, class>
    struct acceptable : Abstract
    {
    	void accept(const typename Abstract::visitor_type& v)
    	{
    		v.visit(*this);
    	}
    };
     
     
    //Classe de base des visiteurs
    //La visite se fait sur le type acceptable qui contient l'information sur le type réel
    template<class, class...>
    struct visitor;
     
    //Récursion
    template<class Abstract, class Concrete, class... Concrete_Tail>
    struct visitor<Abstract,Concrete,Concrete_Tail...>
    	: visitor<Abstract,Concrete_Tail...>
    {
    	using visitor<Abstract,Concrete_Tail...>::visit;
    	virtual void visit(acceptable<Abstract,Concrete>&) const =0;
    };
     
    //Condition d'arrêt
    template<class Abstract, class Concrete>
    struct visitor<Abstract,Concrete>
    {
    	visitor() =default;
    	visitor(const visitor&) =delete;
     
    	virtual ~visitor()
    	{ }
     
    	visitor& operator=(const visitor&) =delete;
     
    	virtual void visit(acceptable<Abstract,Concrete>&) const =0;
    };
     
     
    //Utilitaire pour récupérer le type accepté par la hiérarchie depuis le visiteur
    template<class,class>
    struct accept_type;
     
    template<
    	class Abstract, class... Concrete,
    	class T
    >
    struct accept_type<visitor<Abstract,Concrete...>,T>
    {
    	using type =acceptable<Abstract,T>;
    };
     
     
    //Utilitaire pour récupérer les types concrets de la hiérarchie depuis le visiteur
    template<class>
    struct concrete_type;
     
    template<class Abstract, class... Concrete>
    struct concrete_type<visitor<Abstract,Concrete...>>
    {
    	using type =std::tuple<Concrete...>;
    };
     
     
    //Classe de base qui ajoute accept à la classe de base de la hiérarchie
    template<class Abstract, class... Concrete>
    struct accept_visitor
    {
    	using visitor_type =visitor<Abstract,Concrete...>;
     
    	accept_visitor() =default;
    	accept_visitor(const accept_visitor&) =delete;
     
    	virtual ~accept_visitor()
    	{ }
     
    	accept_visitor& operator=(const accept_visitor&) =delete;
     
    	virtual void accept(const visitor_type&) =0;
    };
     
     
    //Classe dispatcher : c'est un visiteur et un foncteur
     
    //Condition d'arrêt sur les types de la hiérarchie
    template<
    	class To_Visit, class, bool,
    	class Visitor, class,
    	class Fun
    >
    struct dispatcher : Visitor
    {
    	dispatcher(To_Visit& tv, const Fun& f)
    		: to_visit(tv), fun(f)
    	{ }
     
    protected:
    	To_Visit& to_visit;
    	Fun fun;
    };
     
    //Récursion sur les types de la hiérarchie
    template<
    	class To_Visit, class Visited,
    	class Visitor, class T, class... Concrete,
    	class Fun
    >
    struct dispatcher<
    	To_Visit,Visited,false,
    	Visitor,std::tuple<T,Concrete...>,
    	Fun
    >
    	: dispatcher<
    		To_Visit,Visited,false,
    		Visitor,std::tuple<Concrete...>,
    		Fun
    	>
    {
    private:
    	using base =dispatcher<
    		To_Visit,Visited,false,
    		Visitor,std::tuple<Concrete...>,
    		Fun
    	>;
     
    public:
    	using base::base;
     
    	//Déclenche la visite sur le bon paramètre
    	void operator()() const
    	{
    		std::get
    			<std::tuple_size<Visited>::value>
    			(base::to_visit)
    		.accept(*this);
    	}
     
    	using base::visit;
    	void visit(typename accept_type<Visitor,T>::type&) const
    	{
    		using new_visited =typename cat_type<Visited,T>::type;
     
    		//Récursion sur les arguments d'appel
    		dispatcher<
    			To_Visit,new_visited,
    			std::tuple_size<To_Visit>::value == std::tuple_size<new_visited>::value,
    			Visitor,typename concrete_type<Visitor>::type,
    			Fun
    		>(base::to_visit,base::fun)();
    	}
    };
     
    //Condition d'arrêt sur les paramètre d'appel
    template<
    	class To_Visit, class... Visited,
    	class Visitor, class Concrete,
    	class Fun
    >
    struct dispatcher<
    	To_Visit,std::tuple<Visited...>,true,
    	Visitor,Concrete,
    	Fun
    >
    {
    	dispatcher(To_Visit& tv, const Fun& f)
    		: to_visit(tv), fun(f)
    	{ }
     
    	//Déclenche l'appel avec les bon types
    	void operator()()
    	{
    		apply(std::make_index_sequence<sizeof...(Visited)>());
    	}
     
    private:
    	template<std::size_t... I>
    	void apply(std::index_sequence<I...>)
    	{
    		fun(reinterpret_cast<Visited&>(std::get<I>(to_visit))...);
    	}
     
    	To_Visit& to_visit;
    	Fun fun;
    };
     
     
    //Classe de base pour les foncteurs à dispatcher
    template<class Fun, class Abstract>
    struct dispatchable
    {
    	dispatchable() =default;
    	dispatchable(const dispatchable&) =default;
     
    	dispatchable& operator=(const dispatchable&) =default;
     
    	template<class... Arg>
    	void apply(Arg&&... arg)
    	{
    		using used_visitor =typename Abstract::visitor_type;
     
    		auto t =std::forward_as_tuple(std::forward<Arg>(arg)...);
    		dispatcher<
    			decltype(t),std::tuple<>,false,
    			used_visitor,typename concrete_type<used_visitor>::type,
    			Fun
    		>(t,static_cast<Fun&>(*this))();
    	}
     
    protected:
    	~dispatchable()
    	{ }
    };
     
     
    }
     
    #include<iostream>
     
    struct chat;
    struct chien;
     
    struct animal
    	: dispatch::accept_visitor<animal,chat,chien>
    { };
     
    struct chat
    	: dispatch::acceptable<animal,chat>
    { };
     
    struct chien
    	: dispatch::acceptable<animal,chien>
    { };
     
     
    struct attaquer
    	: dispatch::dispatchable<attaquer,animal>
    {
    	void operator()(const chat&, const chat&) const
    	{ std::cout <<  "griffe - griffe" << std::endl;}
    	void operator()(const chat&, const chien&) const
    	{ std::cout <<  "griffe - mord  " << std::endl;}
    	void operator()(const chien&, const chat&) const
    	{ std::cout <<  "mord - griffe" << std::endl;}
    	void operator()(const chien&, const chien&) const
    	{ std::cout << "mord - mord  " << std::endl;}
    };
     
     
    int main()
    {
    	chat c1;
    	chien c2;
     
    	animal& a1 =c1;
    	animal& a2 =c2;
     
    	attaquer().apply(a1,a1);
    	attaquer().apply(a1,a2);
    	attaquer().apply(a2,a1);
    	attaquer().apply(a2,a2);
    }
    C'est pas encore parfait. Typiquement la gestion des retours n'est pas faite et je chercherais bien à découper la fonction visiteur et la fonction foncteur du dispatcher, mais je ne vois pas de solution élégante pour le moment.

  4. #24
    Invité
    Invité(e)
    Par défaut
    Ce qui aurait été parfais c'est de faire quelque chose comme boost::variant mais qui puisse contenir plusieurs objets à la fois et les passer au foncteur mais, je ne sais pas si c'est possible...

  5. #25
    Membre du Club
    Homme Profil pro
    C++
    Inscrit en
    Janvier 2013
    Messages
    45
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : C++

    Informations forums :
    Inscription : Janvier 2013
    Messages : 45
    Points : 44
    Points
    44
    Par défaut
    Salut Flob90,
    Ta version est très intéressante, c'est une belle variante de la version 4 de multiple dispatch.
    - Tu utilises les std::tuples là où j'ai opté pour le parameter_pack.
    - Ton utilisation des "classes/fonctions template utilitaires libres" est très intéressante, et inspirante !

    Comme se doit toute variante, il reste les memes imperfections que celles de la v4 (l'histoire des casts, par exemple).

    La v5 que j'ai publiée plus haut dans le fil du forum les règles toutes, jettes un coup d'oeil !

  6. #26
    Invité
    Invité(e)
    Par défaut
    Au passage, je me demande si, il y a moyen de passer une séquence d'index pour un tuple à un foncteur. (et non pas, tout les index du tuple)
    Ainsi, pas besoin de cast (et je pense qu'il n'y aurait même pas besoin d'une classe de base pour Chien et Chat, il suffit de faire comme un boost::variant, avec le visiteur qui renvoie les index des types trouvé par le visiteur et les passe au foncteur.

    Mais personnellement je ne pense pas que ça soit possible de faire ça, en tout cas je n'ai jamais trouvé de code source qui le fasse.

  7. #27
    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
    C'est quoi exactement l'histoire des cast ? Si c'est juste pour ne pas utiliser de cast, c'est inutile. Un cast n'est pas une erreur si il est utilisé correctement.

    @Lolilolight: Bien entendu qu'on peut faire comme boost.variant, mais la discussion porte sur le mécanisme proposé par l'OP. Pas sur toutes les techniques qui existent pour faire du multi-dispatch.

  8. #28
    Invité
    Invité(e)
    Par défaut
    Je pense qu'il doit s'agir du reinterpret_cast ici :
    Code cpp : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    template<std::size_t... I>
    	void apply(std::index_sequence<I...>)
    	{
    		fun(reinterpret_cast<Visited&>(std::get<I>(to_visit))...);
    	}
     
    	To_Visit& to_visit;
    	Fun fun;

    Et du static cast là :

    Code cpp : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    void apply(Arg&&... arg)
    	{
    		using used_visitor =typename Abstract::visitor_type;
     
    		auto t =std::forward_as_tuple(std::forward<Arg>(arg)...);
    		dispatcher<
    			decltype(t),std::tuple<>,false,
    			used_visitor,typename concrete_type<used_visitor>::type,
    			Fun
    		>(t,static_cast<Fun&>(*this))();
    	}

  9. #29
    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'ai compris après avoir posté (j'ai édité mon message). Un cast n'est pas une erreur, les éviter pour les éviter est inutile. (Par contre je me souviens plus pourquoi j'ai mis un reinterpret et non un static mais il doit y avoir une raison).

  10. #30
    Invité
    Invité(e)
    Par défaut
    Des variants ne serait ce pas mieux ?
    Moi j'utilise deux variants (à la manière c++14) ce qui me permet de me passer du cast, j'ai aussi rajouté cette façon de faire car je ne sais pas laquelle est la meilleure mais pouvoir utiliser les deux façon ça n'est pas mal non plus.

Discussions similaires

  1. Votre avis sur ma bibliothèque
    Par Mikkkka dans le forum C++
    Réponses: 19
    Dernier message: 11/04/2014, 22h11
  2. Votre avis sur l'héritage multiple avec JavaFX
    Par guitariste dans le forum JavaFX
    Réponses: 12
    Dernier message: 02/09/2009, 00h59
  3. votre avis sur les bibliothèques Cappuccino et SproutCore
    Par ClarusAD dans le forum Autres langages pour le Web
    Réponses: 0
    Dernier message: 15/11/2008, 16h23
  4. Réponses: 14
    Dernier message: 12/05/2006, 09h20

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