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

Projets Discussion :

Nouveau moteur de jeux vidéo - présentation et recrutement.


Sujet :

Projets

  1. #21
    Membre actif
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Novembre 2023
    Messages
    236
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur de jeux vidéo

    Informations forums :
    Inscription : Novembre 2023
    Messages : 236
    Par défaut
    Salut je tourne autour de 20 FPS oui à mon avis il y a trop de polygones qui s'affichent.

  2. #22
    Membre actif
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Novembre 2023
    Messages
    236
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur de jeux vidéo

    Informations forums :
    Inscription : Novembre 2023
    Messages : 236
    Par défaut
    Salut, j'ai trouvé le problème pour les ombres qui ne s'affichaient pas correctement, mais, difficile d'avoir quelque chose de parfait parce que le zNear varie suivant la pente et il faut calculer le bonne angle pour incliner l'ombre en fonction de la pente. (Car sinon l'ombre ne s'affiche pas car elle est en dessous de la pente) Bref c'est difficile d'avoir quelque chose de très précis.


  3. #23
    Expert confirmé
    Avatar de Mat.M
    Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2006
    Messages
    8 612
    Détails du profil
    Informations personnelles :
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Novembre 2006
    Messages : 8 612
    Par défaut
    salut 20 fps ? Ah oui ça rame.
    Est-ce que vous avez une machine puissante ?

  4. #24
    Membre actif
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Novembre 2023
    Messages
    236
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur de jeux vidéo

    Informations forums :
    Inscription : Novembre 2023
    Messages : 236
    Par défaut
    Salut! J'ai un intel i5 6 coeurs avec 16GB de RAM et une CG nvidia gforce 1660 super avec 6GB de VRAM. J'ai acheté mon PC il y a 2-3 ans environ. Je ne comprends pas pourquoi le FPS est si bas surtout avec un geometryShader je pensais que ça multiplierait le temps par 6 étant donné que je ne dessine qu'une seule fois la scène au lieu de 6 fois mais on dirait que le CPU attend après le GPU car malgré que j'appelle glDraw une seule fois au lieu de 6 ça ne soulage pas le CPU et au niveau du GPU le nombre de polygones à dessiner reste le même normalement.

  5. #25
    Invité
    Invité(e)
    Par défaut
    Non mais je suis désolé 20fps pour la scène que tu affiches on est en 2024 pas 1990.

    Le problème c'est que tu ne sais pas coder un moteur de jeux.

    C'est pas un mal en soit ce n'est pas donné à tout le monde, enfin là juste afficher une skybox et un terrain avec une ombre mdr quoi.

    Là c'est vraiment un problème structurel.

  6. #26
    Membre actif
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Novembre 2023
    Messages
    236
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur de jeux vidéo

    Informations forums :
    Inscription : Novembre 2023
    Messages : 236
    Par défaut
    Oui enfin ça ne rame pas donc je ne sais pas si mon compteur de FPS est bon enfin soit c'est surtout quand je met ensemble le rendu des ombres, des lumières et de la réfraction que ça consomme du FPS. Je pense que le soucis est le fait que je dessine la scène trop de fois. J'utilise pas mal de textures de rendu pour gérer la transparence. Donc même si je n'ai pas énormément de polys, ça bouffe du FPS.

  7. #27
    Expert confirmé
    Avatar de Mat.M
    Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2006
    Messages
    8 612
    Détails du profil
    Informations personnelles :
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Novembre 2006
    Messages : 8 612
    Par défaut
    @laurent : et avec des jeux commerciaux vous obtenez un mauvais framerate aussi ?
    Avez-vous été voir dans le panneau de configuration de n-vidia ?

  8. #28
    Membre actif
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Novembre 2023
    Messages
    236
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur de jeux vidéo

    Informations forums :
    Inscription : Novembre 2023
    Messages : 236
    Par défaut
    Salut. Je dois voir cela mais avant assassin's Creed Odyssée tournait à 60 de FPS sur mon pc avec les graphismes au max... Il y a sûrement quelque chose que j'ai mal fait... pourtant je n'effectue qu'un seul appel à draw par shader j'ai essayé de réduire le plus possible les appels à draw avec le bindless texturing l'indirect rendering et le batching. Il n'y a que lorsque je change de shader ou de type de primitive que je rappelle le draw. Même si je dessine dans 10 framebuffers la même scène je pensais pas que ça boufferait autant le FPS.

  9. #29
    Responsable 2D/3D/Jeux


    Avatar de LittleWhite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2008
    Messages
    27 245
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

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

    Informations forums :
    Inscription : Mai 2008
    Messages : 27 245
    Billets dans le blog
    174
    Par défaut
    Pour les performances, la vérité se trouve dans les profileurs, ou tout outil qui remonte des données factuels sur le temps pris par telle ou telle fonctionnalité. D'ailleurs, on ne ferait pas d'optimisation sans ces données .
    Vous souhaitez participer à la rubrique 2D/3D/Jeux ? Contactez-moi

    Ma page sur DVP
    Mon Portfolio

    Qui connaît l'erreur, connaît la solution.

  10. #30
    Membre actif
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Novembre 2023
    Messages
    236
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur de jeux vidéo

    Informations forums :
    Inscription : Novembre 2023
    Messages : 236
    Par défaut
    Ok mais quand je compile sur code::blocks avec l'option -pg je n'ai pas de données en sorties du profiler sinon oui j'avais pensé à l'utiliser.

    Je viens de corriger un bug concernant la classe qui récupère toutes les informations sur une classe, j'ai dû trouver un moyen de supprimer tout ce qu'il y avait entre les crochets si il y a du code dans le fichier.hpp ça n'était pas si simple étant donné que dans les crochets des fonctions il pouvait y avoir d'autres crochets pour des if, while, etc...

    Après une fois cela de fait c'est facile de récupérer le nom de la fonction et les arguments.

  11. #31
    Membre actif
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Novembre 2023
    Messages
    236
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur de jeux vidéo

    Informations forums :
    Inscription : Novembre 2023
    Messages : 236
    Par défaut
    Bonjour, je n'arrive pas à faire fonctionner gprof sous code::blocks ça va être un dur de savoir quelle fonction ralenti l'exécution du code. Mais le problème vient sûrement de mes fonctions de dessin.

    Pourtant je ne fait que d'ajouter tout mes sommets dans un VBO avant d'appeler la fonction draw pour tout dessiner en une fois. (Il n'y a que lorsque j'ai des types de primitives ou des shaders différents que je fais plusieurs draws)

    Mais j'utilise pas mal de FBO, maintenant toutes ne dessinent pas forcément tout la scène ça dépend de ce que je passe comme type d'entités à mon composant et si c'est une lumière ou un objet rétractable, etc...

    Mais la chute du FPS provient de mes fonctions de dessins et je ne comprend comment le simple fait d'ajouter des sommets dans un VBO peut faire chuter ainsi le FPS...

    Mais bon il y a deux types de primitives ici, un type pour le terrain des Quads et un pour le modèle 3D des triangles...

    EDIT : Sinon je recherche un programmeur qui s'y connait bien en programmation graphique pour améliorer les performances, résoudre ces problèmes de glitchs et finir l'implémentation VULKAN.

  12. #32
    Membre actif
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Novembre 2023
    Messages
    236
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur de jeux vidéo

    Informations forums :
    Inscription : Novembre 2023
    Messages : 236
    Par défaut
    gprof fonctionne et apparemment c'est les push_back qui font descendre le FPS.

  13. #33
    Responsable 2D/3D/Jeux


    Avatar de LittleWhite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2008
    Messages
    27 245
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

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

    Informations forums :
    Inscription : Mai 2008
    Messages : 27 245
    Billets dans le blog
    174
    Par défaut
    Citation Envoyé par Laurent7601 Voir le message
    gprof fonctionne et apparemment c'est les push_back qui font descendre le FPS.
    Cool. Y a sûrement moyen d'éviter quelques copies
    De plus, de mémoire, un VBO, ça se prépare une fois, pas besoin de copier les données à chaque image, non ?

    EDIT : Sinon je recherche un programmeur qui s'y connait bien en programmation graphique pour améliorer les performances, résoudre ces problèmes de glitchs et finir l'implémentation VULKAN.
    Quel en serait l'intérêt (autrement dit, quelle est la carotte) ?
    Vous souhaitez participer à la rubrique 2D/3D/Jeux ? Contactez-moi

    Ma page sur DVP
    Mon Portfolio

    Qui connaît l'erreur, connaît la solution.

  14. #34
    Membre actif
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Novembre 2023
    Messages
    236
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur de jeux vidéo

    Informations forums :
    Inscription : Novembre 2023
    Messages : 236
    Par défaut
    Salut! Ca dépend ce qu'il me demande faut voir lol.

    Non mais finalement tout seul je m'en sors plutôt bien, j'arrive à corriger des bugs d'affichage (des glitch), maintenant le problème ça reste l'optimisation au niveau du CPU.

    Mais je préfère le faire seul finalement la programmation ça me permet de mieux apprendre comment fonctionne la programmation graphique.

    J'ai enfin pu régler le problème de scintillement des pixels de l'ombre lorsque il y avait quelque chose entre la caméra et l'ombre c'était juste un problème de synchronisation : plusieurs shaders pour le même pixel s'exécutaient en même temps du coup ce qui était lu par un shader n'était pas ce qui avait été écrit précédemment par un autre shader pour un même pixel, je pensais que memoryBarrier et coherent résoudrait le problème mais en fait non il fallait utiliser l'extension interlock arb pour empêcher qu'une autre invocation de shader pour le même pixel lise la valeur de z pendant que une autre invocation de shader pour ce même pixel l'écrive.

    Bref un peu difficile à comprendre encore pour moi la synchronisation au niveau du GPU et de ce que fait exactement memoryBarrier et coherent mais ça ne faisait pas ce à quoi je m'attendais...

  15. #35
    Membre actif
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Novembre 2023
    Messages
    236
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur de jeux vidéo

    Informations forums :
    Inscription : Novembre 2023
    Messages : 236
    Par défaut
    Salut! La chute du FPS provient du resize et de la copie de mes sommets dans le vertex buffer avant le dessin. (Surtout dans le renderer qui dessine la réfraction et la réflexion) Je pense que pour optimiser je dois faire des vbos pour les objets statique (terrains, modèles 3D statiques, etc...) que je ne remet à jour que au début du programme et des vbos pour les objets dynamiques (animations, particules, etc...) que je remet à jour à chaque frame. Et pour les objets statique ne passer que les indices des objets qui sont visible.

  16. #36
    Membre actif
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Novembre 2023
    Messages
    236
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur de jeux vidéo

    Informations forums :
    Inscription : Novembre 2023
    Messages : 236
    Par défaut
    Salut! Par faute de FPS bas je vais faire une pause sur le développement de la 3D, je reprendrais ça plus tard car là, je n'ai pas d'idées pour comment optimiser cela.

    Du coup j'ai repris le développement de l'éditeur (en 2D) et j'ai corriger des bugs avec le plugin de génération de scripts, désormais on peut créer des quêtes par exemple et les ajouter aux pnj grâce à des scripts créé soi même. Une fonctionnalité que je n'ai pas trouvé dans UE et Unity pour ça que je fais mon propre moteur. Je dois encore optimiser mon "runtime compiler" pour ne pas recompiler le code qui ne change pas.

  17. #37
    Membre actif
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Novembre 2023
    Messages
    236
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur de jeux vidéo

    Informations forums :
    Inscription : Novembre 2023
    Messages : 236
    Par défaut
    Salut! J'ai trouvé une idée pour optimiser le moteur, en fait, j'utilise mal les VBO. Je vais ne les remplir que si on ajoute ou supprime des entités mais plus pendant le rendu. Pour les entités dynamique (animations, particules) je vais modifier les sommets dans la VBO à la position de l'entité dans le VBO en m'arrangeant pour avoir des tableaux de sommets à taille fixe. Et je vais à chaque rendu ne mettre à jour que les indices de mes vbo pour ne dessiner que ce qui est visible. Je n'ai pas encore tester je suis seulement entrain de modifier le code mais ça devrait améliorer grandement les perfs.

  18. #38
    Expert confirmé
    Avatar de Mat.M
    Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2006
    Messages
    8 612
    Détails du profil
    Informations personnelles :
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Novembre 2006
    Messages : 8 612
    Par défaut
    Citation Envoyé par Laurent7601 Voir le message
    Je vais ne les remplir que si on ajoute ou supprime des entités mais plus pendant le rendu.
    qu'est-ce que vous entendez par entité ? Je suppose que c'est une mesh 3d ?
    Pourquoi ne pas créer, si c'est déjà le cas, une classe entité statique qui encapsule son propre vertex buffer avec une méhtode render ?

  19. #39
    Membre actif
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Novembre 2023
    Messages
    236
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur de jeux vidéo

    Informations forums :
    Inscription : Novembre 2023
    Messages : 236
    Par défaut
    Et faire un draw call par mesh ? Je pense pas que ça soit très opti.

    J'ai essayé de faire un VBO avec toutes les entités de la scène et stocker la position de l'entité dans le VBO et ne mettre à jour que des indexes à chaque frame mais ça ne fonctionne pas. :/

  20. #40
    Membre actif
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Novembre 2023
    Messages
    236
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur de jeux vidéo

    Informations forums :
    Inscription : Novembre 2023
    Messages : 236
    Par défaut
    Salut! J'ai corrigé une erreur de compilation dans le fichier fastDelegate.h
    Désormais, ce code-ci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    SkillAction skillAction;
              skill.setSkillBehaviour(new FastDelegate<void>(&SkillAction::launchLastHeal, skillAction, static_cast<Hero*>(hero), skill));
    Compile, plus obligé d'utiliser un pointeur sur l'objet pour le pointeur de fonction membre.

    C'était un membre de ce forum qui m'avait proposé ce code que j'ai amélioré. J'ai également supprimé la macro déguelasse avec les void* pour les placeholder et j'ai utilisé du code c++17.

    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
     
    #ifndef ODFAEG_TMP_HPP
    #define ODFAEG_TMP_HPP
    #include <tuple>
    namespace odfaeg {
        namespace core {
                template < typename Tp, typename... List >
                struct contains : std::true_type {};
     
                template < typename Tp, typename Head, typename... Rest >
                struct contains<Tp, Head, Rest...>
                : std::conditional< std::is_same<Tp, Head>::value,
                    std::true_type,
                    contains<Tp, Rest...>
                >::type {};
                template <typename T, typename Tuple>
                struct has_type;
     
                template <typename T>
                struct has_type<T, std::tuple<>> : std::false_type {};
     
                template <typename T, typename U, typename... Ts>
                struct has_type<T, std::tuple<U, Ts...>> : has_type<T, std::tuple<Ts...>> {};
     
                template <typename T, typename... Ts>
                struct has_type<T, std::tuple<T, Ts...>> : std::true_type {};
                template < typename Tp >
                struct contains<Tp> : std::false_type {};
     
                template <typename T, typename U=void, typename... Types>
                constexpr std::size_t index() {
                    return std::is_same<T, U>::value ? 0 : 1 + index<T, Types...>();
                }
                //Make index sequences from an offset.
                template<std::size_t N, typename Seq> struct offset_sequence;
     
                template<std::size_t N, std::size_t... Ints>
                struct offset_sequence<N, std::index_sequence<Ints...>>
                {
                 using type = std::index_sequence<Ints + N...>;
                };
                template<std::size_t N, typename Seq>
                using offset_sequence_t = typename offset_sequence<N, Seq>::type;
                //Concatenate two sequences of indexes into one.
                template<typename Seq1, typename Seq> struct cat_sequence;
                template<std::size_t... Ints1, std::size_t... Ints2>
                struct cat_sequence<std::index_sequence<Ints1...>,
                                    std::index_sequence<Ints2...>>
                {
                 using type = std::index_sequence<Ints1..., Ints2...>;
                };
                template<typename Seq1, typename Seq2>
                using cat_sequence_t = typename cat_sequence<Seq1, Seq2>::type;
                template<typename T, typename Seq>
                struct select_tuple;
                template<typename T, std::size_t... Ints>
                //Return a tuple with elements at indexes.
                struct select_tuple<T, std::index_sequence<Ints...>>
                {
                 using type = std::tuple<std::tuple_element_t<Ints, T>...>;
                };
                //Remove the Nth elements of a tuple.
                template<std::size_t N, typename T>
                struct remove_Nth
                {
                  static constexpr auto size = std::tuple_size_v<T>;
                  using first = std::make_index_sequence<N>;
                  using rest = offset_sequence_t<N+1,
                                std::make_index_sequence<size-N-1>>;
                  using indices = cat_sequence_t<first, rest>;
                  using type = typename select_tuple<T, indices>::type;
                };
                namespace meta {
                    template <std::size_t I, class T, bool B>
                    struct get;
                    template <std::size_t I, class T>
                    struct get <I, T, true>
                    {
                        using type = T;
                    };
                    template <std::size_t I, class T>
                    struct get <I, T, false> {
                        using type = typename remove_Nth<I, T>::type;
                    };
                    template <template<class...> class Pred, class T, bool B, std::size_t NB, class Seq>
                    struct append_if {};
     
                    template <template<class...> class Pred, class T, std::size_t NB, std::size_t IH, std::size_t... IT>
                    struct append_if<Pred, T, true, NB, std::index_sequence<IH, IT...>> {
                        using f = typename append_if<Pred, typename get<IH-NB, T, Pred<std::tuple_element_t<IH-NB, T>>::value>::type, Pred<std::tuple_element_t<IH-NB, T>>::value, NB, std::index_sequence<IT...>>::f;
                    };
                    template <template<class...> class Pred, class T, std::size_t NB, std::size_t IH, std::size_t... IT>
                    struct append_if<Pred, T, false, NB, std::index_sequence<IH, IT...>> {
                        using f = typename append_if<Pred, typename get<IH-NB, T, Pred<std::tuple_element_t<IH-NB, T>>::value>::type, Pred<std::tuple_element_t<IH-NB, T>>::value, NB+1, std::index_sequence<IT...>>::f;
                    };
                    template <template<class...> class Pred, class T, std::size_t NB, std::size_t IH>
                    struct append_if<Pred, T, true, NB, std::index_sequence<IH>> {
                        using f = typename get<IH-NB, T, Pred<std::tuple_element_t<IH-NB, T>>::value>::type;
                    };
                    template <template<class...> class Pred, class T, std::size_t NB, std::size_t IH>
                    struct append_if<Pred, T, false, NB, std::index_sequence<IH>> {
                        using f = typename get<IH-NB, T, Pred<std::tuple_element_t<IH-NB, T>>::value>::type;
                    };
     
                    template<template <class...> class Pred, typename T>
                    struct copy_if {
                        using f = typename append_if<Pred, T, Pred<std::tuple_element_t<0, T>>::value, 0, std::make_index_sequence<std::tuple_size<T>::value>>::f;
                    };
                    template<template <class...> class Pred>
                    struct copy_if <Pred, std::tuple<>> {
                        using f = std::tuple<>;
                    };
     
                    template <std::size_t NB, typename T, bool B, std::size_t IH, std::size_t IH2, std::size_t N>
                    struct remove_if_sames {
     
                    };
     
                    template <std::size_t NB, typename T, std::size_t IH1, std::size_t IH2, std::size_t N>
                    struct remove_if_sames<NB, T, true, IH1, IH2, N> {
                        using f = typename remove_if_sames<NB, typename get<IH2-NB, T, !std::is_same<std::tuple_element_t<IH1, T>, std::tuple_element_t<IH2-NB, T>>::value>::type, !std::is_same<std::tuple_element_t<IH1, T>, std::tuple_element_t<IH2-NB, T>>::value, IH1, IH2+1, N>::f;
                    };
                    template <std::size_t NB, typename T, std::size_t IH1, std::size_t IH2, std::size_t N>
                    struct remove_if_sames<NB, T, false, IH1, IH2, N> {
                        using f = typename remove_if_sames<NB+1, typename get<IH2-NB, T, !std::is_same<std::tuple_element_t<IH1, T>, std::tuple_element_t<IH2-NB, T>>::value>::type, !std::is_same<std::tuple_element_t<IH1, T>, std::tuple_element_t<IH2-NB, T>>::value, IH1, IH2+1, N>::f;
                    };
                    template <std::size_t NB, typename T, std::size_t IH1, std::size_t N>
                    struct remove_if_sames<NB, T, true, IH1, N, N> {
                        using f = typename get<N-NB, T, !std::is_same<std::tuple_element_t<IH1, T>, std::tuple_element_t<N-NB, T>>::value>::type;
                    };
                    template <std::size_t NB, typename T, std::size_t IH1, std::size_t N>
                    struct remove_if_sames<NB, T, false, IH1, N, N> {
                        using f = typename get<N-NB-1, T, !std::is_same<std::tuple_element_t<IH1, T>, std::tuple_element_t<N-NB-1, T>>::value>::type;
                    };
     
     
     
     
                    template <typename T, std::size_t IH, bool B, bool B2>
                    struct make_unique {
                        using f = typename make_unique<typename remove_if_sames<0, T, true, IH, IH+1, std::tuple_size<T>::value-1>::f, IH+1, IH == std::tuple_size<T>::value - 2, (std::tuple_size<T>::value > 1)>::f;
                    };
                    template <typename T, std::size_t IH>
                    struct make_unique<T, IH, false, true> {
                        using f = typename make_unique<typename remove_if_sames<0, T, true, IH, IH+1, std::tuple_size<T>::value-1>::f, IH+1, IH == std::tuple_size<T>::value - 2, (std::tuple_size<T>::value > 1)>::f;
                    };
                    template <typename T, std::size_t IH>
                    struct make_unique<T, IH, true, true> {
                        using f = typename remove_if_sames<0, T, true, IH-1, IH, std::tuple_size<T>::value-1>::f;
                    };
                    template <typename T, std::size_t IH>
                    struct make_unique<T, IH, false, false> {
                        using f = T;
                    };
                    template <typename T>
                    struct unique {
                        using f = typename make_unique<T, 0, false, (std::tuple_size<T>::value > 1)>::f;
                    };
                    template <>
                    struct unique <std::tuple<>> {
                        using f = std::tuple<>;
                    };
                    template <std::size_t I, std::size_t J, class T, bool B>
                    struct swap_if {
                    };
                    template <std::size_t I, std::size_t J, class T>
                    struct swap_if<I, J, T, true> {
                       using first = std::make_index_sequence<I>;
                       using second = std::index_sequence<J>;
                       using third = offset_sequence_t<I+1,std::make_index_sequence<J-I-1>>;
                       using four = std::index_sequence<I>;
                       using last = offset_sequence_t<J+1,std::make_index_sequence<std::tuple_size<T>()-J-1>>;
                       using indices = cat_sequence_t<first, cat_sequence_t<second, cat_sequence_t<third, cat_sequence_t<four, last>>>>;
                       using type = typename select_tuple<T, indices>::type;
                    };
                    template <std::size_t I, std::size_t J, class T>
                    struct swap_if<I, J, T, false> {
                       using type = T;
                    };
                    template <class Comp, typename T, std::size_t IH1, std::size_t IH2, std::size_t N>
                    struct swap_elements {
                       using f = typename swap_elements<Comp, typename swap_if<IH1, IH2, T, !Comp::template f<std::tuple_element_t<IH1, T>, std::tuple_element_t<IH2, T>>::value>::type, IH1, IH2+1, N>::f;
                    };
                    template <class Comp, typename T, std::size_t IH1, std::size_t N>
                    struct swap_elements<Comp, T, IH1, N, N> {
                       using f = typename swap_if<IH1, N, T, !Comp::template f<std::tuple_element_t<IH1, T>, std::tuple_element_t<N, T>>::value>::type;
                    };
                    template <typename Comp, typename T, std::size_t IH, bool B, bool B2>
                    struct sort_impl {
                    };
                    template <typename Comp, typename T, std::size_t IH>
                    struct sort_impl<Comp, T, IH, false, true> {
                        using f = typename sort_impl<Comp, typename swap_elements<Comp, T, IH, IH+1, std::tuple_size<T>::value-1>::f, IH + 1, IH ==  std::tuple_size<T>::value-2, (std::tuple_size<T>::value > 1)>::f;
                    };
                    template <typename Comp, typename T, std::size_t IH>
                    struct sort_impl<Comp, T, IH, true, true> {
                        using f = typename swap_elements<Comp, T, IH-1, IH, std::tuple_size<T>::value-1>::f;
                    };
                    template <typename Comp, typename T, std::size_t IH>
                    struct sort_impl<Comp, T, IH, false, false> {
                        using f = T;
                    };
                    template <typename Comp, typename T>
                    struct sort {
                        using f = typename sort_impl<Comp, T, 0, false, (std::tuple_size<T>::value > 1)>::f;
                    };
                    template <typename Comp>
                    struct sort <Comp, std::tuple<>> {
                        using f = std::tuple<>;
                    };
                    template <class T, template<class...> class R, class Seq>
                    struct lift {
                    };
                    template <class T, template<class...> class R, std::size_t... Ints>
                    struct lift <T, R, std::index_sequence<Ints...>> {
                        using f = R<std::tuple_element_t<Ints, T>...>;
                    };
                }
            //Return a tuple with elements at indexes.
            template <typename T, std::size_t... Ints>
            auto select_tuple_vals(T& tuple, std::index_sequence<Ints...>)
            {
                return std::make_tuple(std::get<Ints>(tuple)...);
            }
     
            //Remove the Nth elements of a tuple.
            template<std::size_t N, typename T>
            auto remove_Nth_vals(T& tuple)
            {
              constexpr auto size = tuple.nbTypes();
              using first = std::make_index_sequence<N>;
              using rest = offset_sequence_t<N+1,
                            std::make_index_sequence<size-N-1>>;
              using indices = cat_sequence_t<first, rest>;
              return select_tuple(tuple, indices{});
            }
     
        }
    }
    #endif
    Ce qui donne :
    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
    288
    289
    290
    291
    292
    293
    294
    295
    296
    297
    298
    299
    300
    301
    302
    303
    304
    305
    306
    307
    308
    309
    310
    311
    312
    313
    314
    315
    316
    317
    318
    319
    320
    321
    322
    323
    324
    325
    326
    327
    328
    329
    330
    331
    332
    333
    334
    335
    336
    337
    338
    339
    340
    341
    342
    343
    344
    345
    346
    347
    348
    349
    350
    351
    352
    353
    354
    355
    356
    357
    358
    359
    360
    361
    362
    363
    364
    365
    366
    367
    368
    369
    370
    371
    372
    373
    374
    375
    376
    377
    378
    379
    380
    381
    382
    383
    384
    385
    386
    387
    388
    389
    390
    391
    392
    393
    394
    395
    396
    397
    398
    399
    400
    401
    402
    403
    404
    405
    406
    407
    408
    409
    410
    411
    412
    413
    414
    415
    416
    417
    418
    419
    420
    421
    422
    423
    424
    425
    426
    427
    428
    429
    430
    431
    432
    433
    434
    435
    436
    437
    438
    439
    440
    441
    442
    443
    444
    445
    446
    447
    448
    449
    450
    451
    452
    453
    454
    455
    456
    457
    458
    459
    460
    461
    462
    463
    464
    465
    466
    467
    468
    469
    470
    471
    472
    473
    474
    475
    476
    477
    478
    479
    480
    481
    482
    483
    484
    485
    486
    487
    488
    489
    490
    491
    492
    493
    494
    495
    496
    497
    498
    499
    500
    501
    502
    503
    504
    505
    506
    507
    508
    509
    510
    511
    512
    513
    514
    515
    516
    517
    518
    519
    520
    521
    522
    523
    524
    525
    526
    527
    528
    529
    530
    531
    532
    533
    534
    535
    536
    537
    538
    539
    540
    541
    542
    543
    544
    545
    546
    547
    548
    549
    550
    551
    552
    553
    554
    555
    556
    557
    558
    559
    560
    561
    562
    563
    564
    565
    566
    567
    568
    569
    570
    571
    572
    573
    574
    575
    576
    577
    578
    579
    580
    581
    582
    583
    584
    585
    586
    587
    588
    589
    590
    591
    592
    593
    594
    595
    596
    597
    598
    599
    600
    601
    602
    603
    604
    605
    606
    607
    608
    609
    610
    611
    612
    613
    614
    615
    616
    617
    618
    619
    620
    621
    622
    623
    624
    625
    626
    627
    628
    629
    630
    631
    632
    633
    634
    635
    636
    637
    638
    639
    640
    641
    642
    643
    644
    645
    646
    647
    648
    649
    650
    651
    652
    653
    654
    655
    656
    657
    658
    659
    660
    661
    662
    663
    664
    665
    666
    667
    668
    669
    670
    671
    672
    673
    674
    675
    676
    677
    678
    679
    680
    681
    682
    683
    684
    685
    686
    687
    688
    689
    690
    691
    692
    693
    694
    695
    696
    697
    698
    699
    700
    701
    702
    703
    704
    705
    706
    707
    708
    709
    710
    711
    712
    713
    714
    715
    716
    717
    718
    719
    720
    721
    722
    723
    724
    725
    726
    727
    728
    729
    730
    731
    732
    733
    734
    735
    736
    737
    738
    739
    740
    741
    742
    743
    744
    745
    746
    747
    748
    749
    750
    751
    752
    753
    754
    755
    756
    757
    758
    759
    760
    761
    762
    763
    764
    765
    766
    767
    768
    769
    770
    771
    772
    773
    774
    775
    776
    777
    778
    779
    780
    781
    782
    783
    784
    785
    786
    787
    788
    789
    790
    791
    792
    793
    794
    795
    796
    797
    798
    799
    800
    801
    802
    803
    804
    805
    806
    807
    808
    809
    810
    811
    812
    813
    814
    815
    816
    817
    818
    819
    820
    821
    822
    823
    824
    825
    826
    827
    828
    829
    830
     
    namespace odfaeg {
        namespace core {
            #ifndef VOIDPTR_DELEGATE_IMPL
            /**
            *  \file  fastDelegate.h
            *  \class Parameter
            *  \brief Hold value for a placeholder.
            *  \param i : the placeholder's position.
            *  \param T : the placeholder's type.
            *  \author Duroisin.L
            *  \version 1.0
            *  \date 1/02/2014
            */
            template<std::size_t i, class T>
            struct Parameter
            {
              T value;
            };
            /**
            *  \file  fastDelegate.h
            *  \class LateParameters
            *  \brief Wrap each placeholders's values using inheritance and variadic template.
            *  \param Placeholders : the placeholders.
            *  \author Duroisin.L
            *  \version 1.0
            *  \date 1/02/2014
            */
            template<class... Placeholders>
            struct LateParameters : Parameter<Placeholders::index, typename Placeholders::type>... {
     
            };
            /**
            *  \file  fastDelegate.h
            *  \class IRefVal
            *  \brief Interface for the warppers to references, values and pointers.
            *  This class is used store references, pointers and values to pass to the callack's functions.
            *  \param T : the type of the value to wrap.
            *  \author Duroisin.L
            *  \version 1.0
            *  \date 1/02/2014
            */
            template<class T, class LateParamsT, bool isCopiable>
            struct IRefVal {
                /**\fn
                *  \brief default constructor
                */
                IRefVal()=default;
                /**\fn T& get()
                *  \brief get the reference of the wrapped type.
                *  \return the reference of the wrapped type.
                */
                virtual T& bind(void* params) = 0;
                virtual T& get() = 0;
                /**\fn std::unique_ptr<IRefVal<T>> clone() const = 0;
                *  \brief copy the wrapper.
                *  \return the copied wrapper.*/
                virtual std::unique_ptr<IRefVal<T, LateParamsT, isCopiable>> clone() const = 0;
                /**\fn destructor*/
                virtual ~IRefVal(){}
     
            protected:
                /**\fn IRefVal(const IRefVal&)
                *  \brief constructor, pass the reference to wrap.
                *  \param const IRefVal& : the reference to wrap.
                */
                IRefVal(const IRefVal&){}
                /** \fn IRefVal& operator=(const IRefVal&)
                *   \brief affector.
                *   \param const IRefVal& : the wrapper to affect.
                *   \return the affected wrapper.*/
                IRefVal& operator=(const IRefVal&)
                { return *this; }
            };
            /**
            *  \file  fastDelegate.h
            *  \class Ref
            *  \brief Warp a reference. (Use std::reference_wrapper so we can pass a reference with std::ref)
            *  \author Duroisin.L
            *  \version 1.0
            *  \date 1/02/2014
            */
            template <typename T, typename LateParamsT, bool isCopiable>
            class RefVal;
            template<class T, typename LateParamsT, bool isCopiable>
            struct Ref : IRefVal<T, LateParamsT, isCopiable> {
                /**
                *\fn Ref(const std::reference_wrapper<T>& r)
                *\brief Constructor : pass an std::reference_wrapper to the wrapper.
                *\param std::reference_wrapper<T>& r : the reference_wrapper.
                */
                Ref(const std::reference_wrapper<T>& r)
                    : ref(r)
                {}
                /**
                * \fn T& bind()
                * \brief return a reference to an object.
                * \param void* address of the wrapper to placeholder's values.
                * \return T& the reference to the object.
                */
                T& bind(void* params) {
                  return ref.get();
                }
                /**
                * \fn T& get()
                * \brief return a reference to an object.
                * \return T& the reference to the object.
                */
                T& get()
                { return ref.get(); }
                /**
                * \fn std::unique_ptr<IRefVal<T>> clone() const
                * \brief copy the reference wrapper.
                * \return std::unique_ptr<IRefVal<T>> : the cloned wrapper.
                */
                std::unique_ptr<IRefVal<T, LateParamsT, isCopiable>> clone() const
                { return std::make_unique<Ref>(*this); }
            private:
                std::reference_wrapper<T> ref; /**> the std::reference_wrapper which warp the reference.*/
            };
            /**
            *  \file  fastDelegate.h
            *  \class Val
            *  \brief Warp a value.
            *  \author Duroisin.L
            *  \version 1.0
            *  \date 1/02/2014
            */
            template<class T, class LateParamsT, bool isCopiable>
            struct Val : IRefVal<T, LateParamsT, isCopiable> {
            };
            template<class T, class LateParamsT>
            struct Val<T, LateParamsT, true> : IRefVal<T, LateParamsT, true> {
                /**\fn Val(const T& t)
                *  \brief pass a value to the wrapper.
                *  \param const T& t : the value to pass.
                */
                Val(const T& t)
                    : val(t)
                {}
                /**
                * \fn T& bind()
                * \brief return a the value.
                * \param void* address of the wrapper to placeholder's values.
                * \return T& the value.
                */
                T& bind(void* params) {
                  return val;
                }
                /** \fn
                *   \brief return the value
                *   \return T& : return the value.
                */
                //template<class = typename std::enable_if_t<std::is_copy_constructible_v<T>>>
                T& get()
                { return val; }
                /*template<class...D, class = typename std::enable_if_t<!std::is_copy_constructible_v<T>>>
                T& get()
                { return std::move(val); }*/
                /**
                * \fn std::unique_ptr<IRefVal<T>> clone() const
                * \brief copy the value wrapper.
                * \return std::unique_ptr<IRefVal<T>> : the cloned wrapper.
                */
                std::unique_ptr<IRefVal<T, LateParamsT, true>> clone() const
                { return std::make_unique<Val>(*this); }
            private:
                T val; /**> T val : keep the value of the wrapper.*/
            };
            template<class T, class LateParamsT>
            struct Val<T, LateParamsT, false> : IRefVal<T, LateParamsT, false> {
                /**\fn Val(const T& t)
                *  \brief pass a value to the wrapper.
                *  \param const T& t : the value to pass.
                */
                Val(const T& t)
                    : val(t)
                {}
                /**
                * \fn T& bind()
                * \brief return a the value.
                * \param void* address of the wrapper to placeholder's values.
                * \return T& the value.
                */
                T& bind(void* params) {
                  return val;
                }
                /** \fn
                *   \brief return the value
                *   \return T& : return the value.
                */
                //template<class = typename std::enable_if_t<std::is_copy_constructible_v<T>>>
                T& get()
                { return std::move(val); }
                /*template<class...D, class = typename std::enable_if_t<!std::is_copy_constructible_v<T>>>
                T& get()
                { return std::move(val); }*/
                /**
                * \fn std::unique_ptr<IRefVal<T>> clone() const
                * \brief copy the value wrapper.
                * \return std::unique_ptr<IRefVal<T>> : the cloned wrapper.
                */
                std::unique_ptr<IRefVal<T, LateParamsT, false>> clone() const
                { return std::make_unique<Val>(*this); }
            private:
                T val; /**> T val : keep the value of the wrapper.*/
            };
            /**
            *  \file  fastDelegate.h
            *  \class ph
            *  \brief user defined placeholders.
            *  \param I placeholder's position.
            *  \param T placeholder's type.
            *  \author Duroisin.L
            *  \version 1.0
            *  \date 1/02/2014
            */
            template<size_t I, class T>
            struct ph
            {
                using type = T; /**> alias to the type.*/
                static constexpr std::size_t index = I; /** > alias to the position.*/
            };
            /**
            *  \file  fastDelegate.h
            *  \class is_placeholder
            *  \brief trait class if the type is not a placeholder the compiler choose this class's version.
            *  \param T the type.
            *  \author Duroisin.L
            *  \version 1.0
            *  \date 1/02/2014
            */
            template<class T>
            struct is_placeholder
            : std::false_type
            {};
            /**
            *  \file  fastDelegate.h
            *  \class is_placeholder
            *  \brief trait class specialization if the type is a placeholder the compiler choose this class's version.
            *  \param T the type.
            *  \author Duroisin.L
            *  \version 1.0
            *  \date 1/02/2014
            */
            template<std::size_t I, class T>
            struct is_placeholder<ph<I, T>>
            : std::true_type
            {};
            /**
            *  \file  fastDelegate.h
            *  \class LessPlaceceholder
            *  \brief class used to sort placeholder's from the first position to the last type's position.
            *  \author Duroisin.L
            *  \version 1.0
            *  \date 1/02/2014
            */
            struct LessPlaceceholder
            {
              template<class PlaceHolder1, class PlaceHolder2>
              using f = std::bool_constant<PlaceHolder1::index < PlaceHolder2::index>; /**> if the first placeholder position is smaller than the second placeholder's position.*/
            };
            /**
            *  \file  fastDelegate.h
            *  \class placeholder
            *  \brief Warp a placeholder.
            *  \param I : the placeholder's position.
            *  \param T : the placeholder's type.
            *  \param LateParamsT : the type of the placeholders holder. (we need to pass it for the cast!)
            *  \author Duroisin.L
            *  \version 1.0
            *  \date 1/02/2014
            */
            template<size_t I, class T, class LateParamsT, bool isCopiable>
            struct placeholder : IRefVal<T, LateParamsT, isCopiable>
            {
                /**
                * \fn std::unique_ptr<IRefVal<T, LateParamsT>> clone() const
                * \brief copy the placeholder wrapper.
                * \return std::unique_ptr<IRefVal<T, LateParamsT>> : the cloned wrapper.
                */
                std::unique_ptr<IRefVal<T, LateParamsT, isCopiable>> clone() const
                { return std::make_unique<placeholder>(*this); }
                /**
                * \fn T& bind(void* params)
                * \brief extract the placeholder's value from the placeholers's holder.
                * \param void* address of the wrapper to placeholder's values.
                * \return T& the value.
                */
                T& bind(void* params) {
                    //We cast from void* to the placeholders's holder type.
                    LateParamsT& paramsT = *static_cast<LateParamsT*>(params);
                    //We cast from base type to the derived type to extract the placeholder's value.
                    return static_cast<Parameter<I, T>&>(paramsT).value;
                }
                /** \fn T& get()
                *   \brief we don't need to return anything, this function is never called anyway.
                *   \return T& : return's nothing.
                */
                T& get()
                {
     
                }
            };
            /**
            *  \file  fastDelegate.h
            *  \class RefVal
            *  \brief Wrap a pointer, a value or a reference and keep a pointer to the generic wrapper.
            *  Call the right constructor depending on the wrapper's or value's type.
            *  \author Duroisin.L
            *  \version 1.0
            *  \date 1/02/2014
            */
            template<class T, class LateParamsT, bool isCopiable>
            struct RefVal {
                /**
                * \fn RefVal (const T& t)
                * \brief constructor : construct a wrapper to a value
                * \param const T& t : the value to
                */
                RefVal(const T& t)
                : rv(std::make_unique<Val<T, LateParamsT, isCopiable>>(t))
                {}
                /**
                * \fn RefVal (const std::reference_wrapper<T>& r)
                * \brief constructor : construct a wrapper to an std::reference_wrapper.
                * \param const std::reference_wrapper<T>& : the std::reference_wrapper to pass.
                */
                RefVal(const std::reference_wrapper<T>& r)
                : rv(std::make_unique<Ref<T, LateParamsT, isCopiable>>(r))
                {}
                /**
                * \fn RefVal (ph<I,T>&&)
                * \brief constructor : construct a wrapper to a placeholder from a user defined placeholder.
                * \param ph<I,T>&& the placeholder.
                */
                template<size_t I>
                RefVal(ph<I,T>&&) //we need to use a different placeholder class here to pass the palceholders's holder type for the static_cast.
                    : rv(std::make_unique<placeholder<I,T,LateParamsT, isCopiable>>())
                {}
                /** \fn RefVal (const RefVal& rhs)
                *   \brief copy constructor, copy the wrapper with the right wrapper type.
                *   \param const RefVal& rhs : the wrapper to copy.
                */
                RefVal(const RefVal& rhs)
                {
                    rv = rhs.rv->clone();
                }
                /** \fn RefVal& operator= (const RefVal& rhs)
                *   \brief affector.
                *   \param const RefVal& rhs : the wrapper to affect.
                */
                RefVal& operator=(const RefVal& rhs)
                { rv=rhs.rv->clone(); return *this; }
                /** \fn T& get() const
                *   \brief get the wrapper.
                *   \return a unique pointer to the generic wrapper interface.
                */
                T& bind(void* params) {
                    return rv->bind(params);
                }
                T& get() const
                { return rv->get(); }
            private:
                std::unique_ptr<IRefVal<T, LateParamsT, isCopiable>> rv; /**> a pointer to the generic wrapper interface.*/
            };
            //Classe de trait pour déterminer le type à stocker
     
            //(Interne) Cas général
            /**
            *  \file  fastDelegate.h
            *  \class ToStoreImpl
            *  \param T the type of the wrapper.
            *  \brief Trait class which use an alias on a wrapped type.
            *  \author Duroisin.L
            *  \version 1.0
            *  \date 1/02/2014
            */
            template<class T>
            struct ToStoreImpl
            { using type = T; };
            /**
            *  \file  fastDelegate.h
            *  \class ToStoreImpl
            *  \param T the type warpped in the warpper.
            *  \brief Trait class with keep an alias on the wrapped type.
            *  This class is specialized for std::_reference_wrapper type.
            *  \author Duroisin.L
            *  \version 1.0
            *  \date 1/02/2014
            */
            template<class T>
            struct ToStoreImpl<std::reference_wrapper<T>>
            { using type = T; };
            /**
            *  \file  fastDelegate.h
            *  \class ToStoreImpl
            *  \param T the type warpped in the warpper.
            *  \brief Trait class with keep an alias on the plcaholder's type.
            *  This class is specialized for placeholder's type.
            *  \author Duroisin.L
            *  \version 1.0
            *  \date 1/02/2014
            */
            template<size_t I, class T>
            struct ToStoreImpl<ph<I,T>>
            { using type = T; };
            /**
            *  \file  fastDelegate.h
            *  \class ToStore
            *  \param T the type of the wrapper.
            *  \brief Trait class with keep an alias of the wrapper type. (without the reference)
            *  the inheritance use the right specialized templated class to hold the type of the wrapped object
            *  depending on the wrapper type.
            *  \author Duroisin.L
            *  \version 1.0
            *  \date 1/02/2014
            */
            template<class T>
            struct ToStore
                : ToStoreImpl<std::remove_reference_t<T>>
            {};
            /**
            *  \file  fastDelegate.h
            *  \class ToStore_t
            *  \param T the type of the wrapped object.
            *  \brief Trait class which hold an alias to the real type of the wrapped type.
            *  \author Duroisin.L
            *  \version 1.0
            *  \date 1/02/2014
            */
            template<class T>
            using ToStore_t = typename
                ToStore<T>::type;
            /**
            *  \file  fastDelegate.h
            *  \class DynamicWrapper
            *  \param R the return type of the wrapped functor.
            *  \param C the class type of the wrapped functor.
            *  \param ArgT the arguments types of the wrapped functor.
            *  \brief This class warp a function pointer to a member function.
            *  I don't use an std::function directly here to keep the class type of the member function pointer
            *  because if the passed object is polymorphic, I need to apply a dynamic cast
            *  before calling the member function pointer on the object.
            *  \author Duroisin.L
            *  \version 1.0
            *  \date 1/02/2014
            */
            template<bool B, class R, class C, class... ArgT>
            struct DynamicWrapper {
            };
            template<class R, class C,class... ArgT>
            struct DynamicWrapper<true, R, C, ArgT...> {
                /**\fn DynamicWrapper(R(C::*pf)(ArgT...)) : pfunc(pf)
                *  \brief warp a pointer to a member function.
                *  \param R(C::*pf)(ArgT...) : the pointer to the member function.
                */
                DynamicWrapper(R(C::*pf)(ArgT...)) : pfunc(pf){}
                template<class O, class... ArgU>
                R operator()(O* o, ArgU&&... arg) const
                {
                    //std::cout<<"class : "<<typeid(C).name()<<std::endl<<"object derived : "<<typeid(o).name()<<std::endl<<"address : "<<o<<std::endl;
                    (o->*pfunc)(std::forward<ArgU>(arg)...);
                }
                template<class O, class... ArgU>
                R operator()(O o, ArgU&&... arg) const
                {
                    //std::cout<<"class : "<<typeid(C).name()<<std::endl<<"object derived : "<<typeid(o).name()<<std::endl<<"address : "<<o<<std::endl;
                    (o.*pfunc)(std::forward<ArgU>(arg)...);
                }
     
                /**\fn R operator()(O o, ArgU&&... arg) const
                *  \brief call the member function's pointer with he given object and the given argument
                *  \param O o : the object onwich to call the member function's pointer.
                *  \param ArgU&& arg : the arguments of the member function's pointer to call.
                */
                /*template<class O, class... ArgU>
                R operator()(O o, ArgU&&... arg) const {
                    return (o.*pfunc)(std::forward<ArgU>(arg)...);
                }*/
            private:
                R (C::*pfunc)(ArgT...); /**> a pointer to a member's function.*/
            };
            template<class R, class C, class... ArgT>
            struct DynamicWrapper<false, R, C, ArgT...> {
                /**\fn DynamicWrapper(R(C::*pf)(ArgT...)) : pfunc(pf)
                *  \brief warp a pointer to a member function.
                *  \param R(C::*pf)(ArgT...) : the pointer to the member function.
                */
                DynamicWrapper(R(C::*pf)(ArgT...)) : pfunc(pf){}
                /**\fn R operator()(O* o, ArgU&&... arg) const
                *  \brief call the member function's pointer witht he given object and the given argument
                *  apply a dynamic_cast in case of the type of the object and the type of the classe containing the member function
                *  are not the same. (If the object is polymoprhic)
                *  If the cast fails it means that the object is not polymorphic so it throws an error.
                *  \param O* o : the object onwich to call the member function's pointer.
                *  \param ArgU&& arg : the arguments of the member function's pointer to call.
                */
                template<class O, class... ArgU>
                R operator()(O* o, ArgU&&... arg) const
                {
                    //std::cout<<"class : "<<typeid(C).name()<<std::endl<<"object derived : "<<typeid(o).name()<<std::endl<<"address : "<<o<<std::endl;
                    if(dynamic_cast<C*>(o))
                        return (dynamic_cast<C*>(o)->*pfunc)(std::forward<ArgU>(arg)...);
                    throw Erreur(0, "Invalid cast : types are nor polymorphic!", 1);
                }
                template<class O, class... ArgU>
                R operator()(O& o, ArgU&&... arg) const
                {
                    //std::cout<<"class : "<<typeid(C).name()<<std::endl<<"object derived : "<<typeid(o).name()<<std::endl<<"address : "<<o<<std::endl;
                    if(dynamic_cast<C&>(o))
                        return (dynamic_cast<C&>(o).*pfunc)(std::forward<ArgU>(arg)...);
                    throw Erreur(0, "Invalid cast : types are nor polymorphic!", 1);
                }
                R (C::*pfunc)(ArgT...);
            };
            /**
            *  \file  fastDelegate.h
            *  \class DynamicFunction
            *  \param F the type of the function.
            *  \brief Generic class for every functors type.
            *  \author Duroisin.L
            *  \version 1.0
            *  \date 1/02/2014
            */
            template<class F>
            class DynamicFunction;
            /**
            *  \file  fastDelegate.h
            *  \class DynamicFunction
            *  \param R the return type of the function.
            *  \param ArgT... the type of the arguments of the function.
            *  \brief Specialized template class for functors. (inherit from std::function)
            *  build a functor with the right constructor depending a the pointer's function type.
            *  \author Duroisin.L
            *  \version 1.0
            *  \date 1/02/2014
            */
            template<class R, class... ArgT>
            class DynamicFunction<R(ArgT...)>
                : std::function<R(ArgT...)>
            {
                /**> just an alias to the type of the base class.*/
                using Base = std::function<R(ArgT...)>;
     
            public:
                /**
                * \fn DynamicFunction(F&& f)
                * \brief pass a functor to the std::function.
                * \param F&& f : the functor to pass to the std::function.
                */
                template<class F>
                DynamicFunction(F&& f) : Base(std::forward<F>(f))
                {}
                /** \fn DynamicFunction (R (C::*pf)(ArgU...))
                *   \brief pass a pointer to a member's function to the DynamicWrapper, and then
                *   pass this wrapper to the std::function, so, the std::function call the operator() of the DynamicWrapper class
                *   and not the operator() of the std::function class so we can perform the dynamic_cast if necessary.
                *   \param R(C::*pf)(ArgU...) : the pointer to the member's function.
                *   \
                */
                template<class C, class... ArgU>
                DynamicFunction(R(C::*pf)(ArgU...))
                    : Base(DynamicWrapper<std::is_same<C, ToStore_t<std::remove_reference_t<std::tuple_element_t<0, std::tuple<ArgT...>>>>>::value, R,C, ArgU...>(pf))
                {}
                /**> we use the operator() of the base class.*/
                using Base::operator();
            };
            /**
            *  \file  fastDelegate.h
            *  \class Delegate
            *  \param R the return type of the function.
            *  \brief Interface with can hold a delegate to every delegates types.
            *  \author Duroisin.L
            *  \version 1.0
            *  \date 1/02/2014
            */
            template<class R>
            struct Delegate {
                /**\fn Delegate()
                *  \brief default constructor.
                */
                Delegate() =default;
                /**\fn virtual std::unique_ptr<Delegate> clone() const = 0;
                *  \brief pure virtual function to redefine in the subclass to copy the delegate.
                *  \return std::unique_ptr<Delegate> a pointer to the copied delegate.
                */
                virtual std::unique_ptr<Delegate> clone() const = 0;
                /**\fn void bind(void* params) = 0;
                *  \brief pure virtual function to redefines to bind parameters.
                *  \param void* : address of placeholders's holder.
                */
                virtual void bind(void* params) = 0;
                /**\fn R operator()() = 0;
                *  \brief pure virtual function to redefines to call the std::function of the delegate.
                *  \return R : return the value returned by the std::function.
                */
                virtual R operator()() = 0;
                /** /fn virtual Delegate()
                * \brief destructor
                */
                virtual ~Delegate(){}
     
            protected:
                /**
                * \fn Delegate (const Delegate&) {}
                * \brief copy constructor.
                * \param const Delegate& : the delegate to copy.
                */
                Delegate(const Delegate&){}
                /**
                * \fn Delegate& operator= (const Delegate&) {}
                * \brief affector.
                * \return Delegate& : return a reference to the current delegate.
                */
                Delegate& operator=(const Delegate&)
                {
                    return *this;
                }
            };
            /**
            *  \file  fastDelegate.h
            *  \class FastDelegateImpl
            *  \brief Implementation of the delegate's interfaces.
            *  \author Duroisin.L
            *  \version 1.0
            *  \date 1/02/2014
            */
            template<class R, class... ArgT>
            struct FastDelegateImpl : Delegate<R> {
                /** \fn FastDelegateImpl(F&& f, ArgU&&... arg)
                *   \brief constructor : create the delegate with the functor and the arguments value passed.
                */
                template<class F, class... ArgU>
                FastDelegateImpl(F&& f, ArgU&&... arg)
                    : func(std::forward<F>(f))
                    , param(std::forward<ArgU>(arg)...)
                    , tmpParam(std::forward<ArgU>(arg)...)
                {}
                /** \fn std::unique_ptr<Delegate<R>> clone() const
                *   \brief make a copy of the delegate.
                *   \return the copied delegate.
                */
                std::unique_ptr<Delegate<R>> clone() const
                { return std::make_unique<FastDelegateImpl>(*this); }
                /** \fn void bind(void* params)
                *   \brief bind each placeholders's parameters's values depending on the placeholders's positions and store them into the tuple.
                *   \param the address of the placeholders's holder.
                */
                void bind(void* params) {
                  param = tmpParam;
                  bindParams(params);
                }
                /** \fn R operator()()
                *   \brief changed the parameter's values of the std::function.
                *   \param ArgU&&... args : the values for the parameters to the delegate's function.
                */
                R operator()()
                { return call(std::make_index_sequence<sizeof...(ArgT)>()); }
                /** \fn setParams(ArgU&&... arg)
                *   \brief change parameters values of the delegate's function.
                *   \param ArgU&&... args : the values for the parameters to the delegate's function.
                */
                template<class... ArgU>
                void setParams(ArgU&&... arg)
                {
                    param=std::make_tuple(std::forward<ArgU>(arg)...);
                    tmpParam=std::make_tuple(std::forward<ArgU>(arg)...);
                }
     
            private:
                /**
                * \fn bindParams(void* params)
                * \brief final case, we stop recursion when each placeholder's parameters are binded.
                * \param the address of the placeholders's holder.
                */
                template <std::size_t I = 0>
                typename std::enable_if<I == sizeof...(ArgT)>::type
                bindParams(void* params) {
     
                }
                /**
                * \fn bindParams(void* params)
                * \brief intermediate case, we do recursion for each tuple elements to bind the placeholders's parameters's values.
                * \param the address of the placeholders's holder.
                */
                template <std::size_t I = 0>
                typename std::enable_if<(I < sizeof...(ArgT))>::type
                bindParams(void* params) {
                    std::get<I>(param) = std::get<I>(param).bind(params);
                    bindParams<I+1>(params);
                }
                /** \fn R call(std::index_sequence<I...>)
                *   \brief pass each elements of the tuple to the std::function and unwarp them.
                *   \param std::index_sequence<I...> : a sequence of indexes to get every elements of the tuple.
                *   \return the value returned by the std::function.
                */
                template<std::size_t... I>
                R call(std::index_sequence<I...>) const
                {
                    return func(std::get<I>(param).get()...);
                }
                DynamicFunction<R(ToStore_t<ArgT>&...)> func; /**> a functor whith hold the pointer to a callback function.*/
                /**
                * We need to remove every types which are not placeholders, we also need to remove same placeholder's types,
                * and finally we also need to sort them.
                * We also remove cv qualifier's and we pass the placeholders's types to the LateParameters class.
                */
                using tuple_t = typename meta::sort<LessPlaceceholder, typename meta::unique<typename meta::copy_if<is_placeholder, std::tuple<std::remove_cv_t<ArgT>...>>::f>::f>::f;
                using late_params_t = typename meta::lift<tuple_t, LateParameters, std::make_index_sequence<std::tuple_size<tuple_t>::value>>::f;    /**> alias to the placeholders's holder.*/
                //We need to use two tuples here, one to store parameters values and another to store parameters values after the placeholders's values are binded.
                //jln lib doesn't compile on mscv so I created my own lib for meta functions.
                /*using late_params_t
          = jln::mp::copy_if<jln::mp::lift<is_placeholder>,
                        jln::mp::unique<jln::mp::sort<LessPlaceceholder,
                                            jln::mp::lift<LateParameters>>>>
            ::f<std::remove_cv_t<ArgT>...>;*/
                std::tuple<RefVal<ToStore_t<ArgT>, late_params_t, std::is_copy_constructible_v<ToStore_t<ArgT>>>...> param; /**> the wrapped values of the parameters to pass to the callback's function.*/
                std::tuple<RefVal<ToStore_t<ArgT>, late_params_t, std::is_copy_constructible_v<ToStore_t<ArgT>>>...> tmpParam; /**> the wrapped values of the temporary parameters (parameters with placeholder's types).*/
            };
            /**
            *  \file  fastDelegate.h
            *  \class FastDelegate
            *  \brief Class used for the type erasure,
            *  which allow the user be able to store a set of different callback's functions types with the same return type.
            * I use this class essentially to connect signals and slots.
            *  \author Duroisin.L
            *  \version 1.0
            *  \date 1/02/2014
            */
            template<class R>
            struct FastDelegate {
                /**\fn default constructor
                */
                FastDelegate() {
                    delegate = nullptr;
                };
                /**\fn FastDelegate (F&& f, Arg&& arf)
                *  \param F&& f : the functor to pass.
                *  \param Arg&&... arg : arguments to pass to the functor.
                */
                template<class F, class... Arg>
                FastDelegate(F&& f, Arg&&... arg) :
                    delegate(std::make_unique
                        <FastDelegateImpl<R,std::remove_reference_t<Arg>...>>
                        (std::forward<F>(f),std::forward<Arg>(arg)...)
                    )
                {}
                /**\fn FastDelegate (FastDelegate& rhs)
                *  \brief copy constructor.
                *  \param FastDelegate& rhs : the delegate to copy.
                */
                FastDelegate(FastDelegate& rhs)
                    : delegate(rhs.delegate->clone())
                {}
                /**\fn FastDelegate (const FastDelegate& rhs)
                *  \brief copy constructor.
                *  \param const FastDelegate& rhs : the delegate to copy.
                */
                FastDelegate(const FastDelegate& rhs)
                    : delegate(rhs.delegate->clone())
                {}
                /**\fn FastDelegate (FastDelegate& rhs)
                *  \brief move constructor.
                *  \param FastDelegate&& rhs : the delegate to move.
                */
                FastDelegate(FastDelegate&& rhs) =default;
                /**\fn FastDelegate& operator= (FastDelegate& rhs)
                *  \brief affect the content of the delegate to the delegate.
                *  \param const FastDelegate& rhs : the delegate affect.
                *  \return FastDelegate& : the affected delegate.
                */
                FastDelegate& operator=(const FastDelegate& rhs)
                { return operator=(FastDelegate(rhs)); }
                /**\fn FastDelegate& operator= (FastDelegate& rhs)
                *  \brief affect and move the content of the delegate to the delegate.
                *  \param const FastDelegate& rhs : the delegate to move and to affect.
                *  \return FastDelegate& : the moved and affected delegate.
                */
                FastDelegate& operator=(FastDelegate&&) =default;
                /**\fn void bind(Arg&&... arg)
                *  \brief bind each arguments for placeholders.
                *  \param the arguments the bind.
                */
                template <typename... Arg>
                void bind(Arg&&... arg)  {
                     void* params = bind_impl(std::index_sequence_for<Arg...>(), static_cast<Arg&&>(arg)...);
                     delegate->bind(params);
                     delete params;
                }
                /**\fn void bind_impl(std::index_sequence<Ints...>, Args&&... args)
                *  \brief bind each arguments for placeholders.
                *  \param std::index_sequence<Ints...> index sequence to pass each arguments.
                *  \param the arguments the bind.
                *  \return pointer to the placeholders's holder's type.
                */
                template<std::size_t... Ints, class... Args>
                void* bind_impl(std::index_sequence<Ints...>, Args&&... args)
                {
                    //Alias to the placeholders's holder's type, we expand the parameter's packs, so the first argument is the type of placeholder 0, and so on.
                    using params_t = LateParameters<ph<Ints, ToStore_t<Args>>...>;
                    void* params = new params_t{static_cast<Args&&>(args)...};
                    return params;
                }
                /**\fn R operator()() const;
                *  \brief call the std::function of the delegate.
                *  \return the value returned by the std::function.
                */
                R operator()()
                {
                    if (delegate)
                        return  (*delegate)();
                }
                /**\fn setParams(Arg&&... arg)
                *  \brief change the parameter's values of the delegate.
                *  \return Arg&&... arg : the values of the parameters of the delegate.
                */
                template<class... Arg>
                void setParams(Arg&&... arg)
                {
                    using DynamicType =
                        FastDelegateImpl<R,std::remove_reference_t<Arg>...>*;
                    if(dynamic_cast<DynamicType>(delegate.get()))
                        dynamic_cast<DynamicType>(delegate.get())->setParams(std::forward<Arg>(arg)...);
                    else
                        throw Erreur(0, "Bad cast!", 5);
                }
            private:
                std::unique_ptr<Delegate<R>> delegate; /**> holds the pointer to the generic delegate.*/
            };
    Au lieu du code déguelasse qu'on m'avait proposé et que l'on m'avait dit qu'il n'y avait pas d'autre façon de faire :

    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
    288
    289
    290
    291
    292
    293
    294
    295
    296
    297
    298
    299
    300
    301
    302
    303
    304
    305
    306
    307
    308
    309
    310
    311
    312
    313
    314
    315
    316
    317
    318
    319
    320
    321
    322
    323
    324
    325
    326
    327
    328
    329
    330
    331
    332
    333
    334
    335
    336
    337
    338
    339
    340
    341
    342
    343
    344
    345
    346
    347
    348
    349
    350
    351
    352
    353
    354
    355
    356
    357
    358
    359
    360
    361
    362
    363
    364
    365
    366
    367
    368
    369
    370
    371
    372
    373
    374
    375
    376
    377
    378
    379
    380
    381
    382
    383
    384
    385
    386
    387
    388
    389
    390
    391
    392
    393
    394
    395
    396
    397
    398
    399
    400
    401
    402
    403
    404
    405
    406
    407
    408
    409
    410
    411
    412
    413
    414
    415
    416
    417
    418
    419
    420
    421
    422
    423
    424
    425
    426
    427
    428
    429
    430
    431
    432
    433
    434
    435
    436
    437
    438
    439
    440
    441
    442
    443
    444
    445
    446
    447
    448
    449
    450
    451
    452
    453
    454
    455
    456
    457
    458
    459
    460
    461
    462
    463
    464
    465
    466
    467
    468
    469
    470
    471
    472
    473
    474
    475
    476
    477
    478
    479
    480
    481
    482
    483
    484
    485
    486
    487
    488
    489
    490
    491
    492
    493
    494
    495
    496
    497
    498
    499
    500
    501
    502
    503
    504
    505
    506
    507
    508
    509
    510
    511
    512
    513
    514
    515
    516
    517
    518
    519
    520
    521
    522
    523
    524
    525
    526
    527
    528
    529
    530
    531
    532
    533
    534
    535
    536
    537
    538
    539
    540
    541
    542
    543
    544
    545
    546
    547
    548
    549
    550
    551
    552
    553
    554
    555
    556
    557
    558
    559
    560
    561
    562
    #define FUN_PARAM void* p0 =nullptr, void* p1 =nullptr, void* p2 =nullptr, void* p3 =nullptr
    #define FWD_PARAM p0,p1,p2,p3
    /**
      *\namespace odfaeg
      * the namespace of the Opensource Development Framework Adapted for Every Games.
      */
    namespace odfaeg {
        namespace core {
            /**
            *  \file  fastDelegate.h
            *  \class IRefVal
            *  \brief Interface for the warppers to references, values and pointers.
            *  This class is used store references, pointers and values to pass to the callack's functions.
            *  \param T : the type of the value to wrap.
            *  \author Duroisin.L
            *  \version 1.0
            *  \date 1/02/2014
            */
            template<class T>
            struct IRefVal {
                /**\fn
                *  \brief default constructor
                */
                IRefVal()=default;
                /**\fn T& get()
                *  \brief get the reference of the wrapped type.
                *  \return the reference of the wrapped type.
                */
                virtual T& bind(FUN_PARAM) = 0;
                virtual T& get(FUN_PARAM) = 0;
                /**\fn std::unique_ptr<IRefVal<T>> clone() const = 0;
                *  \brief copy the wrapper.
                *  \return the copied wrapper.*/
                virtual std::unique_ptr<IRefVal<T>> clone() const = 0;
                /**\fn destructor*/
                virtual ~IRefVal(){}
     
            protected:
                /**\fn IRefVal(const IRefVal&)
                *  \brief constructor, pass the reference to wrap.
                *  \param const IRefVal& : the reference to wrap.
                */
                IRefVal(const IRefVal&){}
                /** \fn IRefVal& operator=(const IRefVal&)
                *   \brief affector.
                *   \param const IRefVal& : the wrapper to affect.
                *   \return the affected wrapper.*/
                IRefVal& operator=(const IRefVal&)
                { return *this; }
            };
            /**
            *  \file  fastDelegate.h
            *  \class Ref
            *  \brief Warp a reference. (Use std::reference_wrapper so we can pass a reference with std::ref)
            *  \author Duroisin.L
            *  \version 1.0
            *  \date 1/02/2014
            */
            template <typename T>
            class RefVal;
            template<class T>
            struct Ref : IRefVal<T> {
                /**
                *\fn Ref(const std::reference_wrapper<T>& r)
                *\brief Constructor : pass an std::reference_wrapper to the wrapper.
                *\param std::reference_wrapper<T>& r : the reference_wrapper.
                */
                Ref(const std::reference_wrapper<T>& r)
                    : ref(r)
                {}
                /**
                * \fn T& get()
                * \brief return a reference to an object.
                * \return T& the reference to the object.
                */
                T& bind(FUN_PARAM) {
                  return ref.get();
                }
                T& get(FUN_PARAM)
                { return ref.get(); }
                /**
                * \fn std::unique_ptr<IRefVal<T>> clone() const
                * \brief copy the reference wrapper.
                * \return std::unique_ptr<IRefVal<T>> : the cloned wrapper.
                */
                std::unique_ptr<IRefVal<T>> clone() const
                { return std::make_unique<Ref>(*this); }
            private:
                std::reference_wrapper<T> ref; /**> the std::reference_wrapper which warp the reference.*/
            };
            /**
            *  \file  fastDelegate.h
            *  \class Val
            *  \brief Warp a value.
            *  \author Duroisin.L
            *  \version 1.0
            *  \date 1/02/2014
            */
            template<class T>
            struct Val : IRefVal<T> {
                /**\fn Val(const T& t)
                *  \brief pass a value to the wrapper.
                *  \param const T& t : the value to pass.
                */
                Val(const T& t)
                    : val(t)
                {}
                /** \fn
                *   \brief return the value
                *   \return T& : return the value.
                */
                T& bind(FUN_PARAM) {
                  return val;
                }
                T& get(FUN_PARAM)
                { return val; }
                /**
                * \fn std::unique_ptr<IRefVal<T>> clone() const
                * \brief copy the value wrapper.
                * \return std::unique_ptr<IRefVal<T>> : the cloned wrapper.
                */
                std::unique_ptr<IRefVal<T>> clone() const
                { return std::make_unique<Val>(*this); }
            private:
                T val; /**> T val : keep the value of the wrapper.*/
            };
            template<size_t I, class T>
            struct ph : IRefVal<T>
            {
                std::unique_ptr<IRefVal<T>> clone() const
                { return std::make_unique<ph>(*this); }
                T& bind(FUN_PARAM) {
                  return *static_cast<T*>
                        (std::get<I>(std::make_tuple(FWD_PARAM)));
                }
                T& get(FUN_PARAM)
                {
                    return *static_cast<T*>
                        (std::get<I>(std::make_tuple(FWD_PARAM)));
                }
            };
            /**
            *  \file  fastDelegate.h
            *  \class Ref
            *  \brief Warp a pointer.
            *  \author Duroisin.L
            *  \version 1.0
            *  \date 1/02/2014
            */
            /**
            *  \file  fastDelegate.h
            *  \class RefVal
            *  \brief Wrap a pointer, a value or a reference and keep a pointer to the generic wrapper.
            *  Call the right constructor depending on the wrapper's or value's type.
            *  \author Duroisin.L
            *  \version 1.0
            *  \date 1/02/2014
            */
            template<class T>
            struct RefVal {
                /**
                * \fn RefVal (const T& t)
                * \brief constructor : construct a wrapper to a value
                * \param const T& t : the value to
                */
                RefVal(const T& t)
                : rv(std::make_unique<Val<T>>(t))
                {}
                /**
                * \fn RefVal (const std::reference_wrapper<T>& r)
                * \brief constructor : construct a wrapper to an std::reference_wrapper.
                * \param const std::reference_wrapper<T>& : the std::reference_wrapper to pass.
                */
                RefVal(const std::reference_wrapper<T>& r)
                : rv(std::make_unique<Ref<T>>(r))
                {}
                /** \fn RefVal (const RefVal& rhs)
                *   \brief copy constructor, copy the wrapper with the right wrapper type.
                *   \param const RefVal& rhs : the wrapper to copy.
                */
                template<size_t I>
                RefVal(ph<I,T>&&)
                    : rv(std::make_unique<ph<I,T>>())
                {}
                RefVal(const RefVal& rhs)
                {
                    rv = rhs.rv->clone();
                }
                /** \fn RefVal& operator= (const RefVal& rhs)
                *   \brief affector.
                *   \param const RefVal& rhs : the wrapper to affect.
                */
                RefVal& operator=(const RefVal& rhs)
                { rv=rhs.rv->clone(); return *this; }
                /** \fn T& get() const
                *   \brief get the wrapper.
                *   \return a unique pointer to the generic wrapper interface.
                */
                T& bind(FUN_PARAM) {
                    return rv->bind(FWD_PARAM);
                }
                template<class... Arg>
                T& get(Arg&&... arg) const
                { return rv->get(std::forward<Arg>(arg)...); }
            private:
                std::unique_ptr<IRefVal<T>> rv; /**> a pointer to the generic wrapper interface.*/
            };
            //Classe de trait pour déterminer le type à stocker
     
            //(Interne) Cas général
            /**
            *  \file  fastDelegate.h
            *  \class ToStoreImpl
            *  \param T the type of the wrapper.
            *  \brief Trait class which use an alias on a wrapped type.
            *  \author Duroisin.L
            *  \version 1.0
            *  \date 1/02/2014
            */
            template<class T>
            struct ToStoreImpl
            { using type = T; };
            /**
            *  \file  fastDelegate.h
            *  \class ToStoreImpl
            *  \param T the type warpped in the warpper.
            *  \brief Trait class with keep an alias on the wrapped type.
            *  This class is specialized for std::_reference_wrapper type.
            *  \author Duroisin.L
            *  \version 1.0
            *  \date 1/02/2014
            */
            template<class T>
            struct ToStoreImpl<std::reference_wrapper<T>>
            { using type = T; };
            template<size_t I, class T>
            struct ToStoreImpl<ph<I,T>>
            { using type = T; };
            /**
            *  \file  fastDelegate.h
            *  \class ToStore
            *  \param T the type of the wrapper.
            *  \brief Trait class with keep an alias of the wrapper type. (without the reference)
            *  the inheritance use the right specialized templated class to hold the type of the wrapped object
            *  depending on the wrapper type.
            *  \author Duroisin.L
            *  \version 1.0
            *  \date 1/02/2014
            */
            template<class T>
            struct ToStore
                : ToStoreImpl<std::remove_reference_t<T>>
            {};
            /**
            *  \file  fastDelegate.h
            *  \class ToStore_t
            *  \param T the type of the wrapped object.
            *  \brief Trait class which hold an alias to the real type of the wrapped type.
            *  \author Duroisin.L
            *  \version 1.0
            *  \date 1/02/2014
            */
            template<class T>
            using ToStore_t = typename
                ToStore<T>::type;
            /**
            *  \file  fastDelegate.h
            *  \class DynamicWrapper
            *  \param R the return type of the wrapped functor.
            *  \param C the class type of the wrapped functor.
            *  \param ArgT the arguments types of the wrapped functor.
            *  \brief This class warp a function pointer to a member function.
            *  I don't use an std::function directly here to keep the class type of the member function pointer
            *  because if the passed object is polymorphic, I need to apply a dynamic cast
            *  before calling the member function pointer on the object.
            *  \author Duroisin.L
            *  \version 1.0
            *  \date 1/02/2014
            */
            template<class R, class C, class... ArgT>
            struct DynamicWrapper {
                /**\fn DynamicWrapper(R(C::*pf)(ArgT...)) : pfunc(pf)
                *  \brief warp a pointer to a member function.
                *  \param R(C::*pf)(ArgT...) : the pointer to the member function.
                */
                DynamicWrapper(R(C::*pf)(ArgT...)) : pfunc(pf){}
                /**\fn R operator()(O* o, ArgU&&... arg) const
                *  \brief call the member function's pointer witht he given object and the given argument
                *  apply a dynamic_cast in case of the type of the object and the type of the classe containing the member function
                *  are not the same. (If the object is polymoprhic)
                *  If the cast fails it means that the object is not polymorphic so it throws an error.
                *  \param O* o : the object onwich to call the member function's pointer.
                *  \param ArgU&& arg : the arguments of the member function's pointer to call.
                */
                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)...);
                    throw Erreur(0, "Invalid cast : types are nor polymorphic!", 1);
                }
            private:
                R (C::*pfunc)(ArgT...); /**> a pointer to a member's function.*/
            };
            /**
            *  \file  fastDelegate.h
            *  \class DynamicFunction
            *  \param F the type of the function.
            *  \brief Generic class for every functors type.
            *  \author Duroisin.L
            *  \version 1.0
            *  \date 1/02/2014
            */
            template<class F>
            class DynamicFunction;
            /**
            *  \file  fastDelegate.h
            *  \class DynamicFunction
            *  \param R the return type of the function.
            *  \param ArgT... the type of the arguments of the function.
            *  \brief Specialized template class for functors. (inherit from std::function)
            *  build a functor with the right constructor depending a the pointer's function type.
            *  \author Duroisin.L
            *  \version 1.0
            *  \date 1/02/2014
            */
            template<class R, class... ArgT>
            class DynamicFunction<R(ArgT...)>
                : std::function<R(ArgT...)>
            {
                /**> just an alias to the type of the base class.*/
                using Base = std::function<R(ArgT...)>;
     
            public:
                /**
                * \fn DynamicFunction(F&& f)
                * \brief pass a functor to the std::function.
                * \param F&& f : the functor to pass to the std::function.
                */
                template<class F>
                DynamicFunction(F&& f) : Base(std::forward<F>(f))
                {}
                /** \fn DynamicFunction (R (C::*pf)(ArgU...))
                *   \brief pass a pointer to a member's function to the DynamicWrapper, and then
                *   pass this wrapper to the std::function, so, the std::function call the operator() of the DynamicWrapper class
                *   and not the operator() of the std::function class so we can perform the dynamic_cast if necessary.
                *   \param R(C::*pf)(ArgU...) : the pointer to the member's function.
                *   \
                */
                template<class C, class... ArgU>
                DynamicFunction(R(C::*pf)(ArgU...))
                    : Base(DynamicWrapper<R,C,ArgU...>(pf))
                {}
                /**> just an allias to the operator() of the base class.*/
                using Base::operator();
            };
            /**
            *  \file  fastDelegate.h
            *  \class Delegate
            *  \param R the return type of the function.
            *  \brief Interface with can hold a delegate to every delegates types.
            *  \author Duroisin.L
            *  \version 1.0
            *  \date 1/02/2014
            */
            template<class R>
            struct Delegate {
                /**\fn Delegate()
                *  \brief default constructor.
                */
                Delegate() =default;
                /**\fn virtual std::unique_ptr<Delegate> clone() const = 0;
                *  \brief pure virtual function to redefine in the subclass to copy the delegate.
                *  \return std::unique_ptr<Delegate> a pointer to the copied delegate.
                */
                virtual std::unique_ptr<Delegate> clone() const = 0;
                /**\fn R operator()() = 0;
                *  \brief pure virtual function to redefines to call the std::function of the delegate.
                *  \return R : return the value returned by the std::function.
                */
                virtual void bind(FUN_PARAM) = 0;
                virtual R operator()(FUN_PARAM) = 0;
                /** /fn virtual Delegate()
                * \brief destructor
                */
                virtual ~Delegate(){}
     
            protected:
                /**
                * \fn Delegate (const Delegate&) {}
                * \brief copy constructor.
                * \param const Delegate& : the delegate to copy.
                */
                Delegate(const Delegate&){}
                /**
                * \fn Delegate& operator= (const Delegate&) {}
                * \brief affector.
                * \return Delegate& : return a reference to the current delegate.
                */
                Delegate& operator=(const Delegate&)
                {
                    return *this;
                }
            };
            /**
            *  \file  fastDelegate.h
            *  \class FastDelegateImpl
            *  \brief Implementation of the delegate's interfaces.
            *  \author Duroisin.L
            *  \version 1.0
            *  \date 1/02/2014
            */
            template<class R, class... ArgT>
            struct FastDelegateImpl : Delegate<R> {
                /** \fn FastDelegateImpl(F&& f, ArgU&&... arg)
                *   \brief constructor : create the delegate with the functor and the arguments value passed.
                */
                template<class F, class... ArgU>
                FastDelegateImpl(F&& f, ArgU&&... arg)
                    : func(std::forward<F>(f))
                    , param(std::forward<ArgU>(arg)...)
                    , tmpParam(std::forward<ArgU>(arg)...)
                {}
                /** \fn std::unique_ptr<Delegate<R>> clone() const
                *   \brief make a copy of the delegate.
                *   \return the copied delegate.
                */
                std::unique_ptr<Delegate<R>> clone() const
                { return std::make_unique<FastDelegateImpl>(*this); }
                /** \fn R operator()()
                *   \brief call the std::function of the delegate.
                *   \return the value returned by the std::function.
                */
                void bind(FUN_PARAM) {
                  param = tmpParam;
                  bindParams(FWD_PARAM);
                }
                R operator()(FUN_PARAM)
                { return call(std::make_index_sequence<sizeof...(ArgT)>(), FWD_PARAM); }
                /** \fn R operator()()
                *   \brief changed the parameter's values of the std::function.
                *   \param ArgU&&... args : the values for the parameters to the delegate's function.
                */
                template<class... ArgU>
                void setParams(ArgU&&... arg)
                {
                    param=std::make_tuple(std::forward<ArgU>(arg)...);
                    tmpParam=std::make_tuple(std::forward<ArgU>(arg)...);
                }
     
            private:
                /** \fn R call(std::index_sequence<I...>)
                *   \brief pass each elements of the tuple to the std::function and unwarp them.
                *   \param std::index_sequence<I...> : a sequence of indexes to get every elements of the tuple.
                *   \return the value returned by the std::function.
                */
                template <std::size_t I = 0, typename... Arg>
                typename std::enable_if<I == sizeof...(ArgT)>::type
                bindParams(Arg&&... arg) {
     
                }
                template <std::size_t I = 0, typename... Arg>
                typename std::enable_if<(I < sizeof...(ArgT))>::type
                bindParams(Arg&&... arg) {
                    std::get<I>(param) = std::get<I>(param).bind(std::forward<Arg>(arg)...);
                    bindParams<I+1>(std::forward<Arg>(arg)...);
                }
                template<std::size_t... I, class... ArgU>
                R call(std::index_sequence<I...>, ArgU&&... args) const
                { return func(std::get<I>(param).get(std::forward<ArgU>(args)...)...); }
                DynamicFunction<R(ArgT&...)> func; /**> a functor whith hold the pointer to a callback function.*/
                std::tuple<RefVal<ArgT>...> param; /**> the wrapped values of the parameters to pass to the callback's function.*/
                std::tuple<RefVal<ArgT>...> tmpParam;
            };
            /**
            *  \file  fastDelegate.h
            *  \class FastDelegate
            *  \brief Class used for the type erasure,
            *  which allow the user be able to store a set of different callback's functions types with the same return type.
            *  \author Duroisin.L
            *  \version 1.0
            *  \date 1/02/2014
            */
            template<class R>
            struct FastDelegate {
                /**\fn default constructor
                */
                FastDelegate() = default;
                /**\fn FastDelegate (F&& f, Arg&& arf)
                *  \param F&& f : the functor to pass.
                *  \param Arg&&... arg : arguments to pass to the functor.
                */
                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)...)
                    )
                {}
                /**\fn FastDelegate (FastDelegate& rhs)
                *  \brief copy constructor.
                *  \param FastDelegate& rhs : the delegate to copy.
                */
                FastDelegate(FastDelegate& rhs)
                    : delegate(rhs.delegate->clone())
                {}
                /**\fn FastDelegate (const FastDelegate& rhs)
                *  \brief copy constructor.
                *  \param const FastDelegate& rhs : the delegate to copy.
                */
                FastDelegate(const FastDelegate& rhs)
                    : delegate(rhs.delegate->clone())
                {}
                /**\fn FastDelegate (FastDelegate& rhs)
                *  \brief move constructor.
                *  \param FastDelegate&& rhs : the delegate to move.
                */
                FastDelegate(FastDelegate&& rhs) =default;
                /**\fn FastDelegate& operator= (FastDelegate& rhs)
                *  \brief affect the content of the delegate to the delegate.
                *  \param const FastDelegate& rhs : the delegate affect.
                *  \return FastDelegate& : the affected delegate.
                */
                FastDelegate& operator=(const FastDelegate& rhs)
                { return operator=(FastDelegate(rhs)); }
                /**\fn FastDelegate& operator= (FastDelegate& rhs)
                *  \brief affect and move the content of the delegate to the delegate.
                *  \param const FastDelegate& rhs : the delegate to move and to affect.
                *  \return FastDelegate& : the moved and affected delegate.
                */
                FastDelegate& operator=(FastDelegate&&) =default;
                /**\fn R operator()() const;
                *  \brief call the std::function of the delegate.
                *  \return the value returned by the std::function.
                */
                template <typename... Arg>
                void bind(Arg&&... arg) const {
                     delegate->bind(&arg...);
                }
                template<class... Arg>
                R operator()(Arg&&... arg) const
                { return (*delegate)(&arg...); }
                /**\fn setParams(Arg&&... arg)
                *  \brief change the parameter's values of the delegate.
                *  \return Arg&&... arg : the values of the parameters of the delegate.
                */
                template<class... Arg>
                void setParams(Arg&&... arg)
                {
                    using DynamicType =
                        FastDelegateImpl<R,ToStore_t<Arg>...>*;
                    if(dynamic_cast<DynamicType>(delegate.get()))
                        dynamic_cast<DynamicType>(delegate.get())->setParams(std::forward<Arg>(arg)...);
                    else
                        throw Erreur(0, "Bad cast!", 5);
                }
            private:
                std::unique_ptr<Delegate<R>> delegate; /**> holds the pointer to the generic delegate.*/
            };
        }
    }
    #endif
    Donc voilà.

Discussions similaires

  1. MANU, un nouveau moteur de jeux vidéo ne nécessitant pas de code
    Par LittleWhite dans le forum Développement 2D, 3D et Jeux
    Réponses: 10
    Dernier message: 12/04/2020, 14h53
  2. Intrinsic : un nouveau moteur de jeux open source basé sur Vulkan
    Par LittleWhite dans le forum Développement 2D, 3D et Jeux
    Réponses: 18
    Dernier message: 23/11/2016, 11h09
  3. Un nouveau moteur de jeux vidéo voit le jour : Lumberyard, développé par Amazon
    Par LittleWhite dans le forum Développement 2D, 3D et Jeux
    Réponses: 6
    Dernier message: 11/02/2016, 15h02
  4. Paladin : un nouveau projet de moteur de jeux par la communauté Mozilla.
    Par LittleWhite dans le forum Développement 2D, 3D et Jeux
    Réponses: 19
    Dernier message: 09/09/2011, 12h40
  5. Creer un nouveau moteur de jeux
    Par khenissi dans le forum Moteurs de jeux vidéo
    Réponses: 4
    Dernier message: 28/07/2010, 14h54

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