Bonjour, c'est un code que j'ai repris d'ici (et donc il n'est pas de moi) :
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
 
 //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()
            {
            }
        };
J'aimerais le généraliser pour pouvoir écrire un dispatchable pour plusieurs familles d'objets comme ceci :

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
 
struct chat  : acceptable<animal, chat> {};
struct chien : acceptable<animal, chien> {};
 
struct epée  : acceptable<arme, epée> {};
struct arc   : acceptable<arme, arc> {};
 
struct laser : acceptable<projectile, laser> {};
struct balle : acceptable<projectile, balle> {};
 
struct interaction : dispatchable<interaction, animal, arme, projectile>
{
    void operator()(const chat&, const epée&, const laser&) const { ... }
    void operator()(const chien&, const arc&, const balle&) const { ... }
    // etc.
};
Mais, je ne sais pas faire et j'ai vraiment du mal à comprendre le code de la métaprogrammation en c++.
(Parce que on ne vois pas le code généré lors de la compilation déjà, faut le deviner)

Merci.