| 12
 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
 
 |  
#ifndef Multiple_Dispatch_Via_Visitor_Wrapper_h
#define Multiple_Dispatch_Via_Visitor_Wrapper_h
/************************************************************************
 Project : Multiple Dispatch Wrappers
 File    : multiple_dispatch.h ,
           Single header, sans fonctionnalité avancée
 
 Author  : HARBULOT Julien
 
 Copyright (C) 2014 HARBULOT Julien Edmond René
 
 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.
 
 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 email : info [at] julienh.fr
 
 ************************************************************************
 * Système de multiple dispatch à N arguments (pour tout N > 0)
 *
 * Utilisation :
 *  Chaque classe dont on voudra reconnaître le type implémente le
 *  pattern visitor [aka : elle possède une methode accept(...) ]
 *  Les wrappers prennent un nombre quelconque d'arguments et une action.
 *  Ils s'occupent de retrouver le type de tous les arguments via leurs
 *  méthodes accept(...), puis apellent l'action demandée.
 *
 * Version : 4 - std::tuple
 
 ************************************************************************/
 
 
#include <tuple>
 
//========================================================================
//================================ LIBRARY ===============================
//========================================================================
namespace dispatch{
namespace multiple_dispatch_impl{
 
    //====================================================================
    //====================================================================
    //
    // === Family ===
    //
 
    // A partir du type BaseClass, un dispatcher doit retrouver le bon type dérivé.
    // Pour cela, il doit connaitre la liste des types dérivés (DerivedList)
    // Et il doit pouvoir visiter la hiérarchie en héritant de VisitorBase
    // Ces données constituent une famille :
 
    template <class VisitorBase, class BaseClass, class... DerivedList>
    struct Family{
        template <class... Ts> struct L;
 
        using Visitor = VisitorBase;
        using Base = BaseClass;
        using Deriveds = L<DerivedList...>;
        //using ToList = L<VisitorBase, BaseClass, DerivedList...>;
    };
 
    //====================================================================
    //====================================================================
    //
    // === Multiple Dispatch class ===
    //
 
    template
    <
    class Action, class Data_t,
    size_t nFamilyToProcess, size_t curFamilyIndex, // MaxN et CurN
    class... Families
    >
    struct MultiDisp;
 
    //
    // On écrit : methodeGenerique(BaseClass1* d1, BaseClass2* d2, BaseClass3* d3, ...)
    // Et le MultiDisp appelle : ActionSpecifique(Derivee1A* d1a, Derivee2A*, d2a, Derivee3B*, d3b)
    //
    // Pour ce faire, le MultiDisp doit retrouver le type dérivé de ses nFamilyToProcess arguments.
    // Or, pour retrouver un type dérivé au sein d'une hiérarchie (Family), le MultiDisp
    //   implémente les fonctions visit() d'un curVisitor dont il hérite, action pour laquelle il doit connaitre
    //   toutes les classes dérivées possibles (DerivedList) de la hiérarchie.
 
    // Principe de résolution :
    // On a des pointeurs vers les classes mères d'une part (dans Data_t).
    // On a une liste de familles d'autre part (dans le parameter_pack).
    //
    // Le type des pointeurs ne change qu'au dernier moment (Data_t ne change pas).
    // Ce qui change, c'est notre parameter_pack qui fonctionne comme une file :
    // On enlève une famille à traiter au début (Step 1) et on ajoute le type trouvé a la fin (Step 2).
    // Ensuite, il suffit de caster chaque pointeur vers le type trouvé qui lui correspond (Condition d'arrêt).
    //
    // Pour savoir où on en est dans la file, on utilise deux index : CurN (index courant) et MaxN (nb familles)
    // Lorsque CurN == MaxN, on a traité toute la file
    //    et le parameter_pack ne contient plus que les types trouvés.
 
    // Nomenclature :
    // Une famille est representée par un parameter_pack de la facon suivante :
    // Family<curVisitor , curBase , DerivedList...>
    // L'avantage d'une telle représentation est de pouvoir utiliser le filtrage de motif sur DerivedList :
    // Family<DerivedList...> = Family<DerivedHead, DerivedTail...>
 
    //Step 1 :
    // On itère sur les derivées de la famille F1 pour implémenter les fonctions visit(...)
    // A chaque étape, la liste <DerivedTail...> décroit.
 
    template
    <
    class A, class D_t,
    size_t MaxN, size_t CurN,
    class curVisitor, class curBase, class DerivedHead, class... DerivedTail,
    class... otherFamilies
    >
 
    struct MultiDisp<A, D_t, MaxN, CurN, Family<curVisitor, curBase, DerivedHead, DerivedTail...> , otherFamilies...>
    : public MultiDisp<A, D_t, MaxN, CurN, Family<curVisitor, curBase, DerivedTail...>, otherFamilies...> //on enleve DHead
    {
    protected:
        using Parent = MultiDisp<A, D_t, MaxN, CurN, Family<curVisitor, curBase, DerivedTail...>, otherFamilies...>;
 
    public:
        using Parent::Parent;
        using Parent::visit;
        void visit(DerivedHead*){
            // On arrive dans cette fonction après avoir déclanché la visite (Step 2).
            // A ce stade, on a trouvé le type du pointeur correspondant à la famille CurN.
            // Le type trouvé (DerivedHead) est alors stocké à la fin de la file.
            // La recherche se poursuit pour les familles suivantes.
            // (Rappel : cas d'arrêt quand MaxN = CurN, (cf Condition d'arret)
            MultiDisp<A, D_t, MaxN, CurN+1, otherFamilies..., DerivedHead> next{ Parent::data };
            next.action();
        }
    };
 
    //Step 2 :
    // Fin de l'itération sur la famille courante : plus de dérivées.
    // On va utiliser le pattern visitor pour trouver le bon type dérivé.
    // Pour ce faire, on hérite du bon VisitorBase (curVisitorBase) et on visite le
    //    bon pointeur (dont on connait l'index CurN).
    //
    // La procédure se poursuit quand on arrive dans la bonne fonction visit(DerivedHead*)
    //    (voir plus haut).
    template
    <
    class A, class Data_t,
    size_t MaxN, size_t CurN,
    class curVisitorBase, class curBase,
    class... otherFamilies
    >
 
    struct MultiDisp<A, Data_t, MaxN, CurN, Family<curVisitorBase, curBase> , otherFamilies...>
    : public curVisitorBase
    {
    protected:
        Data_t const& data;
    public:
        MultiDisp(Data_t const& data) : data(data) {}
        void action(){
            std::get<CurN>(data)->accept(this);
        }
    };
 
    //Condition d'arrêt :
    // Quand CurN == MaxN, toutes les familles ont été visitées.
    // Comme à chaque fois les types trouvés ont été placés à la fin de la file,
    //    le parameter_pack <Families...> est devenu <KnownTypes...>.
    // Il nous reste à appeler l'action sur tous les arguments, après
    //    les avoir castés vers le bon type.
    template
    <
    class Action, class Data_t,
    size_t nbTypes,
    class... KnownTypes
    >
    struct MultiDisp<Action, Data_t, nbTypes, nbTypes, KnownTypes...>{
    protected:
        Data_t const& data;
    public:
        MultiDisp(Data_t const& data) : data(data) {}
 
        void action(){
            actionHelper(std::make_index_sequence<nbTypes>{});
        }
    private:
        template <size_t... I>
        void actionHelper(std::index_sequence<I...>){
            Action action;
            action(dynamic_cast<KnownTypes*>(std::get<I>(data))...); //@TODO
        }
    };
 
 
    // ===================================
    // Interface / gestion des pointeurs :
    //
    // Les pointeurs sont gérés par un std::tuple<BaseClass*...>
    // Pour éviter la duplication, c'est cette classe qui garde les pointeurs en mémoire.
    // On s'occupe aussi d'initialiser les index.
 
    template <class Action, class... Families>
    struct Dispatcher{
    private:
        using Data_t = std::tuple<typename Families::Base* ...>;
        using DispatcherImpl = MultiDisp<Action, Data_t, sizeof...(Families), 0, Families...>;
 
        Data_t data;
    public:
        Dispatcher(Action* a, typename Families::Base* ... to_solve)
        : data{to_solve...} {
        }
        void operator()(){
            DispatcherImpl{data}.action();
        }
    };
 
} //namespace implementation
 
using multiple_dispatch_impl::Family;
using multiple_dispatch_impl::Dispatcher;
 
} //namespace public
 
#endif // defined Multiple_Dispatch_Via_Visitor_Wrapper_h */ | 
Partager