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

C++ Discussion :

enum comme clé dans une map


Sujet :

C++

  1. #1
    Membre à l'essai
    Homme Profil pro
    Inscrit en
    Janvier 2012
    Messages
    45
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations forums :
    Inscription : Janvier 2012
    Messages : 45
    Points : 23
    Points
    23
    Par défaut enum comme clé dans une map
    Bonjour!

    J'ai programmé pas mal en Java et j'essai de retranscrire une application java en C++ (je connais le C++ j'en ai fait longtemps mais j'ai arrété).

    J'ai un problème, je ne sais pas du tout pourquoi.

    J'utilise une enumeration comme clé dans une map et ça ne plait pas au compilateur ^^

    Enfin un exemple vaut mieux qu'un long discours.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
     
    #include <map>
     
    enum class Test{
        T1,
        T2
    };
     
    int main ( int argc, char** argv ){
        std::map<Test,float> t_map;
        Test e = Test::T1;
        float s = t_map[e];
    }
    Voici l'erreur:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    (x86)\codeblocks\mingw\bin\..\lib\gcc\mingw32\4.4.1\include\c++\bits\stl_function.h||In member function 'bool std::less<_Tp>::operator()(const _Tp&, const _Tp&) const [with _Tp = Test]':|
    c:\program files (x86)\codeblocks\mingw\bin\..\lib\gcc\mingw32\4.4.1\include\c++\bits\stl_map.h|449|instantiated from '_Tp& std::map<_Key, _Tp, _Compare, _Alloc>::operator[](const _Key&) [with _Key = Test, _Tp = float, _Compare = std::less<Test>, _Alloc = std::allocator<std::pair<const Test, float> >]'|
    C:\Users\Cedric\ProgrammesC++\GAME\main.cpp|20|instantiated from here|
    c:\program files (x86)\codeblocks\mingw\bin\..\lib\gcc\mingw32\4.4.1\include\c++\bits\stl_function.h|230|error: invalid operands of types 'const Test' and 'const Test' to binary 'operator<'|
    ||=== Build finished: 1 errors, 1 warnings (0 minutes, 22 seconds) ===|
    Merci beaucoup pour vos réponse

  2. #2
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 115
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 115
    Points : 32 967
    Points
    32 967
    Billets dans le blog
    4
    Par défaut
    Bonsoir,

    avant même de parler de la map, enum class Test ?!?
    Tu crées un enum ou une classe ? décide-toi. Mais cette ligne me parait pour le moins suspect. (pour ne pas dire carrément fausse).

    Ensuite, il faut qu'un opérateur < soit défini pour le type utilisé en clé dans une map.
    Btw, un enum c'est rien de plus que des noms à des entiers, donc déclarer int en clé fera l'affaire.
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  3. #3
    Membre éclairé

    Homme Profil pro
    Non disponible
    Inscrit en
    Décembre 2012
    Messages
    478
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Non disponible

    Informations forums :
    Inscription : Décembre 2012
    Messages : 478
    Points : 877
    Points
    877
    Billets dans le blog
    1
    Par défaut
    enum class Test ?!?
    Bonsoir, c++11 le permet apparemment.

    http://www.cprogramming.com/c++11/c+...num-class.html

    On peut même choisir le type de l'enum.

  4. #4
    Membre à l'essai
    Homme Profil pro
    Inscrit en
    Janvier 2012
    Messages
    45
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations forums :
    Inscription : Janvier 2012
    Messages : 45
    Points : 23
    Points
    23
    Par défaut
    enum class existe.

    Si j'ai fait ça c'est parceque j'ai plusieurs enum dans mon code qui utilisent le meme nom de constante:

    Attr::TEXT et aussi ContentType::TEXT


    Je ne souhaite pas utiliser de int dans ma map mais un type particulier, dans ce cas là une enum car je souhaite pas que l'on puisse rentrer n'importe quoi à l'interieur de la map.

  5. #5
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 115
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 115
    Points : 32 967
    Points
    32 967
    Billets dans le blog
    4
    Par défaut
    Je ne suis pas au fait des "évolutions" C++11.
    Avoir plusieurs enum du même nom n'a jamais dérangé : namespace et struct permettent de les différencier.

    Je ne suis pas certain que mettre un enum en type de map permettent de s'assurer qu'aucune clé interdite soit utilisée. Il vaudrait mieux pour ça proposer une fonction de check d'insertion.
    L'enum permet uniquement de nommer des valeurs, mais il me semble avoir aperçu une nouveauté du type "enum fortement typé". Peut-être que ça pourrait fonctionner..

    En tous cas l'erreur est toujours la même invalid operands of types 'const Test' and 'const Test' to binary 'operator<', la clé nécessite d'avoir une surcharge de l'opérateur < (cf mon précédent message).
    Peut-on surcharger les oéprateurs pour des enums ?
    edit: apparement oui, donc y'a plus qu'à
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  6. #6
    Membre expert
    Avatar de Klaim
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Août 2004
    Messages
    1 717
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur de jeux vidéo
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 1 717
    Points : 3 344
    Points
    3 344
    Par défaut
    enum class EST un enum fortement type. En gros c'est un enum qui n'a pas de cast implicit vers les entiers et dont les noms sont dans le scope de l'enum.

    Donc en gros, le code propose devrais marcher, que ce soit un enum ou un enum class.

    Exemple: http://ideone.com/36NKPI
    Ca marche aussi la: http://coliru.stacked-crooked.com/
    Ainsi que la: http://rise4fun.com/vcpp

    Donc en gros ça marche.
    L'erreur que tu montres indique que le type en clé n'a pas d’opérateur <, qui est utilise pour ordonner les différentes valeurs.

    Donc, pour résoudre ton problème. dans l’immédiat, ajoute cette fonction avant de déclarer la map:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
        bool operator<( const Test& left, const Test& right )
        { return static_cast<int>(left) < static_cast<int>(right); }
    Mais c'est du bricolage.

    Quelle version de quel compilateur utilises tu?
    EDIT> vu dans le log d'erreur: mingw32\4.4.1

    Ok donc ton problème c'est que tu utilises un très vieux compilateur......

  7. #7
    Membre à l'essai
    Homme Profil pro
    Inscrit en
    Janvier 2012
    Messages
    45
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations forums :
    Inscription : Janvier 2012
    Messages : 45
    Points : 23
    Points
    23
    Par défaut
    Merci pour vos réponse, donc la question serait, où est ce que je peux faire une "mise à jour" d'un compilateur C++? Sachant que j'ai téléchargé la dernière version de CodeBlocks recemment mais ça ne doit pas être suffisant.

  8. #8
    Expert confirmé
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2012
    Messages
    1 711
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2012
    Messages : 1 711
    Points : 4 442
    Points
    4 442
    Par défaut
    Citation Envoyé par van noctar Voir le message
    Merci pour vos réponse, donc la question serait, où est ce que je peux faire une "mise à jour" d'un compilateur C++? Sachant que j'ai téléchargé la dernière version de CodeBlocks recemment mais ça ne doit pas être suffisant.
    Par ici

  9. #9
    Membre chevronné Avatar de Astraya
    Homme Profil pro
    Consommateur de café
    Inscrit en
    Mai 2007
    Messages
    1 043
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France

    Informations professionnelles :
    Activité : Consommateur de café
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mai 2007
    Messages : 1 043
    Points : 2 234
    Points
    2 234
    Par défaut
    Je me demande d'abord pourquoi utiliser une enum comme clé de map?
    enum étant sur ton exemple est un entier ( sauf si tu veux spécifier un type différent et si tu retires ton "class") dans ce cas la. Un vecteur sera beaucoup plus performant avec l'accès vectur[enum].
    Homer J. Simpson


  10. #10
    Membre expert
    Avatar de Klaim
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Août 2004
    Messages
    1 717
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur de jeux vidéo
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 1 717
    Points : 3 344
    Points
    3 344
    Par défaut
    Citation Envoyé par Astraya Voir le message
    Je me demande d'abord pourquoi utiliser une enum comme clé de map?
    enum étant sur ton exemple est un entier ( sauf si tu veux spécifier un type différent et si tu retires ton "class") dans ce cas la. Un vecteur sera beaucoup plus performant avec l'accès vectur[enum].
    Un enum n'a pas forcement les valeurs qui se suivent et ne commencent pas forcement par 0. La c'est un exemple pour montrer le propleme donc c'est simple, mais dans la pratique, je ne vois pas du tout ce qui te gene d'utiliser un enum en clee de map. Que ce soit un enum un pointeur ou un entier, ca reviens au meme techniquement et selon ce que tu essaies de faire l'un est plus approprie que les autres.

  11. #11
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Salut,

    D'abord, l'erreur de compilation:

    Le compilateur te dit qu'il n'existe pas d'opérateur de comparaison '<' pour ta classe test, or, c'est un prérequis indispensable pour les collections associatives (std::map et std::set) du fait de leur mécanique basée sur un arbre binaire.

    Résous ce problème, et tu pourras utiliser ton énumération (fortement typée) comme clé dans une map

    Ceci dit, je ne suis pas particulièrement persuadé de l'intérêt d'utiliser une énumération comme clé dans une std::map

    En effet, une std::map est surtout une collection associative qui met une clé en relation avec une valeur et qui assure que la recherche aura, au pire des cas, une complexité en O(log(n)).

    L'énorme intérêt est de pouvoir utiliser "un très grand nombre" de clés tout en garantissant l'unicité des clés et en gardant une complexité de recherche intéressante

    Par contre, le but des énumérations (qu'elles soient "classiques" ou "fortement typées") reste de disposer de... valeurs énumérées.

    Une valeur énumérée n'est finalement "rien d'autre" qu'une valeur numérique entière constante (déterminée à la compilation, ce qui ne gache rien )à laquelle on a donné un nom afin de la rendre plus explicite.

    Mais, surtout, les valeurs énumérées au sein d'une même énumération ont cette particularité d'être successive: la première vaut 0, la deuxième 1 et la Nieme N-1, du moins, tant que l'on ne lui donne pas une valeurs spécifique.

    On pourrait donc s'en servir comme un index parce que l'on a, justement, la certitude qu'il n'y a pas de "trou" entre les valeurs.

    Et il y a un accès qui offre une complexité encore plus avantageuse que la recherche dichotomique: l'accès direct, qui offre un accès en temps constant ( O(1) ).

    Et comme les choses sont bien faite, cet accès est disponible pour les tableaux (Cstyle ou std::vector).

    Dés lors, à partir du moment où tu t'arranges pour pouvoir déterminer si une valeur est valide (quitte à ce que ce soit de manière totalement arbitraire), tu peux parfaitement utiliser un tableau de valeur et y accéder en utilisant la valeur énumérée comme index.

    C'est d'autant plus vrai que ta ligne de code a un comportement qui ne correspond exactement au fait de renvoyer une valeur considérée comme invalide.

    En effet, l'opérateur [] de std::map a pour résultat d'insérer une nouvelle paire clé - valeur si la clé n'a pas été trouvée avant de te renvoyer la valeur correspondante.

    Ainsi, si tu as déjà inséré e dans ta map, tu récupéreras la valeur insérée, mais, si e correspond à une clé qui n'a pas encore été insérée, tu obtiendras, dans le meilleur des cas, une valeur nulle (float(0) ).

    Dés lors, un tableau présente réellement tous les avantages:
    • L'unicité des index qui correspond à l'unicité des clés dans la map
    • un accès en temps constant si tu te base sur l'index au lieu d'une recherche en O(log(n)) pour la std::map
    • une meilleure représentation en mémoire, de nature à éviter les "cache miss"
    • la possibilité de définir exactement le nombre d'éléments que peut contenir ton tableau
    Maintenant, j'ai donné mes arguments, que je défendrai en cas de besoin, mais c'est toujours à toi de choisir
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  12. #12
    Membre expert
    Avatar de Klaim
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Août 2004
    Messages
    1 717
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur de jeux vidéo
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 1 717
    Points : 3 344
    Points
    3 344
    Par défaut
    koala> Encore une fois, tous les enum ne sont pas designe pour avoir des valeurs qui se suivent. Je trouve que c'est vraiment ignorer le contexte d'utilisation que de donner de tels conseils. J'ai un projet qui a des enums dont plus de la moitiee ne peuvent pas avoir de valeurs qui se suivent. Comment je fais le jour ou j'ai besoin de chercher une valeur relative a une valeur d'un de ces enums? Je fais un vector enorme avec des trous?

    Franchement, je trouve le commentaire sur les enum en clee a la fois hors sujet et misleading (comment on dis ca en francais). En particulier quand on parle d'enum class ou on ne compte pas utiliser la valeur, la plupart du temps, comme un entier.

    Bref, sans connaitre le contexte, ce discours ne vaut rien.

  13. #13
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Ben, oui, et non...

    Je suis d'accord avec le fait que je n'ai pas tenu compte du contexte.

    Mais, même s'il peut, effectivement, y avoir des trous dans les valeurs et même si l'on peut considérer le cas particulier ou chaque valeur énumérée est représentable sur un seul bit (qu'elle sert de "flag" non exclusif), une énumération reste malgré tout un domaine dans lequel tu vas définir un nombre de valeur relativement restreint et globalement bien défini.

    C'est d'autant plus vrai lorsqu'on prend conscience du fonctionnement de l'opérateur [] pour les map

    Les tableaux associatifs de manière générale sont plutôt destinés à la gestion d'éléments dont le nombre est beaucoup moins bien défini, ou à être utilisés lorsqu'il est impossible d'avoir recours à l'accès direct.

    Il y aura bien sur toujours des exceptions en fonction du contexte, mais le principe de base d'utiliser "le bon type pour le bon usage" prévaut quand même très largement
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  14. #14
    Membre expert
    Avatar de Klaim
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Août 2004
    Messages
    1 717
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur de jeux vidéo
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 1 717
    Points : 3 344
    Points
    3 344
    Par défaut
    Voyons, ce n'est pas rare du tout, il suffit de regarder le code de protocoles reseaux! Exemple concret: voici le contenu possible du premier byte d'un packet construit avec la bibliotheque RakNet (qui fait plein de trucs pour toi en arriere plan):

    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
    enum DefaultMessageIDTypes
    {
    	//
    	// RESERVED TYPES - DO NOT CHANGE THESE
    	// All types from RakPeer
    	//
    	/// These types are never returned to the user.
    	/// Ping from a connected system.  Update timestamps (internal use only)
    	ID_CONNECTED_PING,  
    	/// Ping from an unconnected system.  Reply but do not update timestamps. (internal use only)
    	ID_UNCONNECTED_PING,
    	/// Ping from an unconnected system.  Only reply if we have open connections. Do not update timestamps. (internal use only)
    	ID_UNCONNECTED_PING_OPEN_CONNECTIONS,
    	/// Pong from a connected system.  Update timestamps (internal use only)
    	ID_CONNECTED_PONG,
    	/// A reliable packet to detect lost connections (internal use only)
    	ID_DETECT_LOST_CONNECTIONS,
    	/// C2S: Initial query: Header(1), OfflineMesageID(16), Protocol number(1), Pad(toMTU), sent with no fragment set.
    	/// If protocol fails on server, returns ID_INCOMPATIBLE_PROTOCOL_VERSION to client
    	ID_OPEN_CONNECTION_REQUEST_1,
    	/// S2C: Header(1), OfflineMesageID(16), server GUID(8), HasSecurity(1), Cookie(4, if HasSecurity)
    	/// , public key (if do security is true), MTU(2). If public key fails on client, returns ID_PUBLIC_KEY_MISMATCH
    	ID_OPEN_CONNECTION_REPLY_1,
    	/// C2S: Header(1), OfflineMesageID(16), Cookie(4, if HasSecurity is true on the server), clientSupportsSecurity(1 bit),
    	/// handshakeChallenge (if has security on both server and client), remoteBindingAddress(6), MTU(2), client GUID(8)
    	/// Connection slot allocated if cookie is valid, server is not full, GUID and IP not already in use.
    	ID_OPEN_CONNECTION_REQUEST_2,
    	/// S2C: Header(1), OfflineMesageID(16), server GUID(8), mtu(2), doSecurity(1 bit), handshakeAnswer (if do security is true)
    	ID_OPEN_CONNECTION_REPLY_2,
    	/// C2S: Header(1), GUID(8), Timestamp, HasSecurity(1), Proof(32)
    	ID_CONNECTION_REQUEST,
    	/// RakPeer - Remote system requires secure connections, pass a public key to RakPeerInterface::Connect()
    	ID_REMOTE_SYSTEM_REQUIRES_PUBLIC_KEY,
    	/// RakPeer - We passed a public key to RakPeerInterface::Connect(), but the other system did not have security turned on
    	ID_OUR_SYSTEM_REQUIRES_SECURITY,
    	/// RakPeer - Wrong public key passed to RakPeerInterface::Connect()
    	ID_PUBLIC_KEY_MISMATCH,
    	/// RakPeer - Same as ID_ADVERTISE_SYSTEM, but intended for internal use rather than being passed to the user.
    	/// Second byte indicates type. Used currently for NAT punchthrough for receiver port advertisement. See ID_NAT_ADVERTISE_RECIPIENT_PORT
    	ID_OUT_OF_BAND_INTERNAL,
    	/// If RakPeerInterface::Send() is called where PacketReliability contains _WITH_ACK_RECEIPT, then on a later call to
    	/// RakPeerInterface::Receive() you will get ID_SND_RECEIPT_ACKED or ID_SND_RECEIPT_LOSS. The message will be 5 bytes long,
    	/// and bytes 1-4 inclusive will contain a number in native order containing a number that identifies this message.
    	/// This number will be returned by RakPeerInterface::Send() or RakPeerInterface::SendList(). ID_SND_RECEIPT_ACKED means that
    	/// the message arrived
    	ID_SND_RECEIPT_ACKED,
    	/// If RakPeerInterface::Send() is called where PacketReliability contains UNRELIABLE_WITH_ACK_RECEIPT, then on a later call to
    	/// RakPeerInterface::Receive() you will get ID_SND_RECEIPT_ACKED or ID_SND_RECEIPT_LOSS. The message will be 5 bytes long,
    	/// and bytes 1-4 inclusive will contain a number in native order containing a number that identifies this message. This number
    	/// will be returned by RakPeerInterface::Send() or RakPeerInterface::SendList(). ID_SND_RECEIPT_LOSS means that an ack for the
    	/// message did not arrive (it may or may not have been delivered, probably not). On disconnect or shutdown, you will not get
    	/// ID_SND_RECEIPT_LOSS for unsent messages, you should consider those messages as all lost.
    	ID_SND_RECEIPT_LOSS,
     
     
    	//
    	// USER TYPES - DO NOT CHANGE THESE
    	//
     
    	/// RakPeer - In a client/server environment, our connection request to the server has been accepted.
    	ID_CONNECTION_REQUEST_ACCEPTED,
    	/// RakPeer - Sent to the player when a connection request cannot be completed due to inability to connect. 
    	ID_CONNECTION_ATTEMPT_FAILED,
    	/// RakPeer - Sent a connect request to a system we are currently connected to.
    	ID_ALREADY_CONNECTED,
    	/// RakPeer - A remote system has successfully connected.
    	ID_NEW_INCOMING_CONNECTION,
    	/// RakPeer - The system we attempted to connect to is not accepting new connections.
    	ID_NO_FREE_INCOMING_CONNECTIONS,
    	/// RakPeer - The system specified in Packet::systemAddress has disconnected from us.  For the client, this would mean the
    	/// server has shutdown. 
    	ID_DISCONNECTION_NOTIFICATION,
    	/// RakPeer - Reliable packets cannot be delivered to the system specified in Packet::systemAddress.  The connection to that
    	/// system has been closed. 
    	ID_CONNECTION_LOST,
    	/// RakPeer - We are banned from the system we attempted to connect to.
    	ID_CONNECTION_BANNED,
    	/// RakPeer - The remote system is using a password and has refused our connection because we did not set the correct password.
    	ID_INVALID_PASSWORD,
    	// RAKNET_PROTOCOL_VERSION in RakNetVersion.h does not match on the remote system what we have on our system
    	// This means the two systems cannot communicate.
    	// The 2nd byte of the message contains the value of RAKNET_PROTOCOL_VERSION for the remote system
    	ID_INCOMPATIBLE_PROTOCOL_VERSION,
    	// Means that this IP address connected recently, and can't connect again as a security measure. See
    	/// RakPeer::SetLimitIPConnectionFrequency()
    	ID_IP_RECENTLY_CONNECTED,
    	/// RakPeer - The sizeof(RakNetTime) bytes following this byte represent a value which is automatically modified by the difference
    	/// in system times between the sender and the recipient. Requires that you call SetOccasionalPing.
    	ID_TIMESTAMP,
        /// RakPeer - Pong from an unconnected system.  First byte is ID_UNCONNECTED_PONG, second sizeof(RakNet::TimeMS) bytes is the ping,
    	/// following bytes is system specific enumeration data.
    	/// Read using bitstreams
    	ID_UNCONNECTED_PONG,
    	/// RakPeer - Inform a remote system of our IP/Port. On the recipient, all data past ID_ADVERTISE_SYSTEM is whatever was passed to
    	/// the data parameter
    	ID_ADVERTISE_SYSTEM,
    	// RakPeer - Downloading a large message. Format is ID_DOWNLOAD_PROGRESS (MessageID), partCount (unsigned int),
    	///  partTotal (unsigned int),
    	/// partLength (unsigned int), first part data (length <= MAX_MTU_SIZE). See the three parameters partCount, partTotal
    	///  and partLength in OnFileProgress in FileListTransferCBInterface.h
    	ID_DOWNLOAD_PROGRESS,
     
    	/// ConnectionGraph2 plugin - In a client/server environment, a client other than ourselves has disconnected gracefully.
    	///   Packet::systemAddress is modified to reflect the systemAddress of this client.
    	ID_REMOTE_DISCONNECTION_NOTIFICATION,
    	/// ConnectionGraph2 plugin - In a client/server environment, a client other than ourselves has been forcefully dropped.
    	///  Packet::systemAddress is modified to reflect the systemAddress of this client.
    	ID_REMOTE_CONNECTION_LOST,
    	/// ConnectionGraph2 plugin: Bytes 1-4 = count. for (count items) contains {SystemAddress, RakNetGUID, 2 byte ping}
    	ID_REMOTE_NEW_INCOMING_CONNECTION,
     
    	/// FileListTransfer plugin - Setup data
    	ID_FILE_LIST_TRANSFER_HEADER,
    	/// FileListTransfer plugin - A file
    	ID_FILE_LIST_TRANSFER_FILE,
    	// Ack for reference push, to send more of the file
    	ID_FILE_LIST_REFERENCE_PUSH_ACK,
     
    	/// DirectoryDeltaTransfer plugin - Request from a remote system for a download of a directory
    	ID_DDT_DOWNLOAD_REQUEST,
     
    	/// RakNetTransport plugin - Transport provider message, used for remote console
    	ID_TRANSPORT_STRING,
     
     	/// ReplicaManager plugin - Create an object
    	ID_REPLICA_MANAGER_CONSTRUCTION,
     	/// ReplicaManager plugin - Changed scope of an object
     	ID_REPLICA_MANAGER_SCOPE_CHANGE,
     	/// ReplicaManager plugin - Serialized data of an object
    	ID_REPLICA_MANAGER_SERIALIZE,
     	/// ReplicaManager plugin - New connection, about to send all world objects
    	ID_REPLICA_MANAGER_DOWNLOAD_STARTED,
     	/// ReplicaManager plugin - Finished downloading all serialized objects
    	ID_REPLICA_MANAGER_DOWNLOAD_COMPLETE,
     
    	/// RakVoice plugin - Open a communication channel
    	ID_RAKVOICE_OPEN_CHANNEL_REQUEST,
    	/// RakVoice plugin - Communication channel accepted
    	ID_RAKVOICE_OPEN_CHANNEL_REPLY,
    	/// RakVoice plugin - Close a communication channel
    	ID_RAKVOICE_CLOSE_CHANNEL,
    	/// RakVoice plugin - Voice data
    	ID_RAKVOICE_DATA,
     
    	/// Autopatcher plugin - Get a list of files that have changed since a certain date
    	ID_AUTOPATCHER_GET_CHANGELIST_SINCE_DATE,
    	/// Autopatcher plugin - A list of files to create
    	ID_AUTOPATCHER_CREATION_LIST,
    	/// Autopatcher plugin - A list of files to delete
    	ID_AUTOPATCHER_DELETION_LIST,
    	/// Autopatcher plugin - A list of files to get patches for
    	ID_AUTOPATCHER_GET_PATCH,
    	/// Autopatcher plugin - A list of patches for a list of files
    	ID_AUTOPATCHER_PATCH_LIST,
    	/// Autopatcher plugin - Returned to the user: An error from the database repository for the autopatcher.
    	ID_AUTOPATCHER_REPOSITORY_FATAL_ERROR,
    	/// Autopatcher plugin - Returned to the user: The server does not allow downloading unmodified game files.
    	ID_AUTOPATCHER_CANNOT_DOWNLOAD_ORIGINAL_UNMODIFIED_FILES,
    	/// Autopatcher plugin - Finished getting all files from the autopatcher
    	ID_AUTOPATCHER_FINISHED_INTERNAL,
    	ID_AUTOPATCHER_FINISHED,
    	/// Autopatcher plugin - Returned to the user: You must restart the application to finish patching.
    	ID_AUTOPATCHER_RESTART_APPLICATION,
     
    	/// NATPunchthrough plugin: internal
    	ID_NAT_PUNCHTHROUGH_REQUEST,
    	/// NATPunchthrough plugin: internal
    	//ID_NAT_GROUP_PUNCHTHROUGH_REQUEST,
    	/// NATPunchthrough plugin: internal
    	//ID_NAT_GROUP_PUNCHTHROUGH_REPLY,
    	/// NATPunchthrough plugin: internal
    	ID_NAT_CONNECT_AT_TIME,
    	/// NATPunchthrough plugin: internal
    	ID_NAT_GET_MOST_RECENT_PORT,
    	/// NATPunchthrough plugin: internal
    	ID_NAT_CLIENT_READY,
    	/// NATPunchthrough plugin: internal
    	//ID_NAT_GROUP_PUNCHTHROUGH_FAILURE_NOTIFICATION,
     
    	/// NATPunchthrough plugin: Destination system is not connected to the server. Bytes starting at offset 1 contains the
    	///  RakNetGUID destination field of NatPunchthroughClient::OpenNAT().
    	ID_NAT_TARGET_NOT_CONNECTED,
    	/// NATPunchthrough plugin: Destination system is not responding to ID_NAT_GET_MOST_RECENT_PORT. Possibly the plugin is not installed.
    	///  Bytes starting at offset 1 contains the RakNetGUID  destination field of NatPunchthroughClient::OpenNAT().
    	ID_NAT_TARGET_UNRESPONSIVE,
    	/// NATPunchthrough plugin: The server lost the connection to the destination system while setting up punchthrough.
    	///  Possibly the plugin is not installed. Bytes starting at offset 1 contains the RakNetGUID  destination
    	///  field of NatPunchthroughClient::OpenNAT().
    	ID_NAT_CONNECTION_TO_TARGET_LOST,
    	/// NATPunchthrough plugin: This punchthrough is already in progress. Possibly the plugin is not installed.
    	///  Bytes starting at offset 1 contains the RakNetGUID destination field of NatPunchthroughClient::OpenNAT().
    	ID_NAT_ALREADY_IN_PROGRESS,
    	/// NATPunchthrough plugin: This message is generated on the local system, and does not come from the network.
    	///  packet::guid contains the destination field of NatPunchthroughClient::OpenNAT(). Byte 1 contains 1 if you are the sender, 0 if not
    	ID_NAT_PUNCHTHROUGH_FAILED,
    	/// NATPunchthrough plugin: Punchthrough succeeded. See packet::systemAddress and packet::guid. Byte 1 contains 1 if you are the sender,
    	///  0 if not. You can now use RakPeer::Connect() or other calls to communicate with this system.
    	ID_NAT_PUNCHTHROUGH_SUCCEEDED,
     
    	/// ReadyEvent plugin - Set the ready state for a particular system
    	/// First 4 bytes after the message contains the id
    	ID_READY_EVENT_SET,
    	/// ReadyEvent plugin - Unset the ready state for a particular system
    	/// First 4 bytes after the message contains the id
    	ID_READY_EVENT_UNSET,
    	/// All systems are in state ID_READY_EVENT_SET
    	/// First 4 bytes after the message contains the id
    	ID_READY_EVENT_ALL_SET,
    	/// \internal, do not process in your game
    	/// ReadyEvent plugin - Request of ready event state - used for pulling data when newly connecting
    	ID_READY_EVENT_QUERY,
     
    	/// Lobby packets. Second byte indicates type.
    	ID_LOBBY_GENERAL,
     
    	// RPC3, RPC4 error
    	ID_RPC_REMOTE_ERROR,
    	/// Plugin based replacement for RPC system
    	ID_RPC_PLUGIN,
     
    	/// FileListTransfer transferring large files in chunks that are read only when needed, to save memory
    	ID_FILE_LIST_REFERENCE_PUSH,
    	/// Force the ready event to all set
    	ID_READY_EVENT_FORCE_ALL_SET,
     
    	/// Rooms function
    	ID_ROOMS_EXECUTE_FUNC,
    	ID_ROOMS_LOGON_STATUS,
    	ID_ROOMS_HANDLE_CHANGE,
     
    	/// Lobby2 message
    	ID_LOBBY2_SEND_MESSAGE,
    	ID_LOBBY2_SERVER_ERROR,
     
    	/// Informs user of a new host GUID. Packet::Guid contains this new host RakNetGuid. The old host can be read out using BitStream->Read(RakNetGuid) starting on byte 1
    	/// This is not returned until connected to a remote system
    	/// If the oldHost is UNASSIGNED_RAKNET_GUID, then this is the first time the host has been determined
    	ID_FCM2_NEW_HOST,
    	/// \internal For FullyConnectedMesh2 plugin
    	ID_FCM2_REQUEST_FCMGUID,
    	/// \internal For FullyConnectedMesh2 plugin
    	ID_FCM2_RESPOND_CONNECTION_COUNT,
    	/// \internal For FullyConnectedMesh2 plugin
    	ID_FCM2_INFORM_FCMGUID,
    	/// \internal For FullyConnectedMesh2 plugin
    	ID_FCM2_UPDATE_MIN_TOTAL_CONNECTION_COUNT,
    	/// A remote system (not necessarily the host) called FullyConnectedMesh2::StartVerifiedJoin() with our system as the client
    	/// Use FullyConnectedMesh2::GetVerifiedJoinRequiredProcessingList() to read systems
    	/// For each system, attempt NatPunchthroughClient::OpenNAT() and/or RakPeerInterface::Connect()
    	/// When this has been done for all systems, the remote system will automatically be informed of the results
    	/// \note Only the designated client gets this message
    	/// \note You won't get this message if you are already connected to all target systems
    	/// \note If you fail to connect to a system, this does not automatically mean you will get ID_FCM2_VERIFIED_JOIN_FAILED as that system may have been shutting down from the host too
    	/// \sa FullyConnectedMesh2::StartVerifiedJoin()
    	ID_FCM2_VERIFIED_JOIN_START,
    	/// \internal The client has completed processing for all systems designated in ID_FCM2_VERIFIED_JOIN_START
    	ID_FCM2_VERIFIED_JOIN_CAPABLE,
    	/// Client failed to connect to a required systems notified via FullyConnectedMesh2::StartVerifiedJoin()
    	/// RakPeerInterface::CloseConnection() was automatically called for all systems connected due to ID_FCM2_VERIFIED_JOIN_START 
    	/// Programmer should inform the player via the UI that they cannot join this session, and to choose a different session
    	/// \note Server normally sends us this message, however if connection to the server was lost, message will be returned locally
    	/// \note Only the designated client gets this message
    	ID_FCM2_VERIFIED_JOIN_FAILED,
    	/// The system that called StartVerifiedJoin() got ID_FCM2_VERIFIED_JOIN_CAPABLE from the client and then called RespondOnVerifiedJoinCapable() with true
    	/// AddParticipant() has automatically been called for this system
    	/// Use GetVerifiedJoinAcceptedAdditionalData() to read any additional data passed to RespondOnVerifiedJoinCapable()
    	/// \note All systems in the mesh get this message
    	/// \sa RespondOnVerifiedJoinCapable()
    	ID_FCM2_VERIFIED_JOIN_ACCEPTED,
    	/// The system that called StartVerifiedJoin() got ID_FCM2_VERIFIED_JOIN_CAPABLE from the client and then called RespondOnVerifiedJoinCapable() with false
    	/// CloseConnection() has been automatically called for each system connected to since ID_FCM2_VERIFIED_JOIN_START.
    	/// The connection is NOT automatically closed to the original host that sent StartVerifiedJoin()
    	/// Use GetVerifiedJoinRejectedAdditionalData() to read any additional data passed to RespondOnVerifiedJoinCapable()
    	/// \note Only the designated client gets this message
    	/// \sa RespondOnVerifiedJoinCapable()
    	ID_FCM2_VERIFIED_JOIN_REJECTED,
     
    	/// UDP proxy messages. Second byte indicates type.
    	ID_UDP_PROXY_GENERAL,
     
    	/// SQLite3Plugin - execute
    	ID_SQLite3_EXEC,
    	/// SQLite3Plugin - Remote database is unknown
    	ID_SQLite3_UNKNOWN_DB,
    	/// Events happening with SQLiteClientLoggerPlugin
    	ID_SQLLITE_LOGGER,
     
    	/// Sent to NatTypeDetectionServer
    	ID_NAT_TYPE_DETECTION_REQUEST,
    	/// Sent to NatTypeDetectionClient. Byte 1 contains the type of NAT detected.
    	ID_NAT_TYPE_DETECTION_RESULT,
     
    	/// Used by the router2 plugin
    	ID_ROUTER_2_INTERNAL,
    	/// No path is available or can be established to the remote system
    	/// Packet::guid contains the endpoint guid that we were trying to reach
    	ID_ROUTER_2_FORWARDING_NO_PATH,
    	/// \brief You can now call connect, ping, or other operations to the destination system.
    	///
    	/// Connect as follows:
    	///
    	/// RakNet::BitStream bs(packet->data, packet->length, false);
    	/// bs.IgnoreBytes(sizeof(MessageID));
    	/// RakNetGUID endpointGuid;
    	/// bs.Read(endpointGuid);
    	/// unsigned short sourceToDestPort;
    	/// bs.Read(sourceToDestPort);
    	/// char ipAddressString[32];
    	/// packet->systemAddress.ToString(false, ipAddressString);
    	/// rakPeerInterface->Connect(ipAddressString, sourceToDestPort, 0,0);
    	ID_ROUTER_2_FORWARDING_ESTABLISHED,
    	/// The IP address for a forwarded connection has changed
    	/// Read endpointGuid and port as per ID_ROUTER_2_FORWARDING_ESTABLISHED
    	ID_ROUTER_2_REROUTED,
     
    	/// \internal Used by the team balancer plugin
    	ID_TEAM_BALANCER_INTERNAL,
    	/// Cannot switch to the desired team because it is full. However, if someone on that team leaves, you will
    	///  get ID_TEAM_BALANCER_TEAM_ASSIGNED later.
    	/// For TeamBalancer: Byte 1 contains the team you requested to join. Following bytes contain NetworkID of which member
    	ID_TEAM_BALANCER_REQUESTED_TEAM_FULL,
    	/// Cannot switch to the desired team because all teams are locked. However, if someone on that team leaves,
    	///  you will get ID_TEAM_BALANCER_SET_TEAM later.
    	/// For TeamBalancer: Byte 1 contains the team you requested to join.
    	ID_TEAM_BALANCER_REQUESTED_TEAM_LOCKED,
    	ID_TEAM_BALANCER_TEAM_REQUESTED_CANCELLED,
    	/// Team balancer plugin informing you of your team. Byte 1 contains the team you requested to join. Following bytes contain NetworkID of which member.
    	ID_TEAM_BALANCER_TEAM_ASSIGNED,
     
    	/// Gamebryo Lightspeed integration
    	ID_LIGHTSPEED_INTEGRATION,
     
    	/// XBOX integration
    	ID_XBOX_LOBBY,
     
    	/// The password we used to challenge the other system passed, meaning the other system has called TwoWayAuthentication::AddPassword() with the same password we passed to TwoWayAuthentication::Challenge()
    	/// You can read the identifier used to challenge as follows:
    	/// RakNet::BitStream bs(packet->data, packet->length, false); bs.IgnoreBytes(sizeof(RakNet::MessageID)); RakNet::RakString password; bs.Read(password);
    	ID_TWO_WAY_AUTHENTICATION_INCOMING_CHALLENGE_SUCCESS,
    	ID_TWO_WAY_AUTHENTICATION_OUTGOING_CHALLENGE_SUCCESS,
    	/// A remote system sent us a challenge using TwoWayAuthentication::Challenge(), and the challenge failed.
    	/// If the other system must pass the challenge to stay connected, you should call RakPeer::CloseConnection() to terminate the connection to the other system. 
    	ID_TWO_WAY_AUTHENTICATION_INCOMING_CHALLENGE_FAILURE,
    	/// The other system did not add the password we used to TwoWayAuthentication::AddPassword()
    	/// You can read the identifier used to challenge as follows:
    	/// RakNet::BitStream bs(packet->data, packet->length, false); bs.IgnoreBytes(sizeof(MessageID)); RakNet::RakString password; bs.Read(password);
    	ID_TWO_WAY_AUTHENTICATION_OUTGOING_CHALLENGE_FAILURE,
    	/// The other system did not respond within a timeout threshhold. Either the other system is not running the plugin or the other system was blocking on some operation for a long time.
    	/// You can read the identifier used to challenge as follows:
    	/// RakNet::BitStream bs(packet->data, packet->length, false); bs.IgnoreBytes(sizeof(MessageID)); RakNet::RakString password; bs.Read(password);
    	ID_TWO_WAY_AUTHENTICATION_OUTGOING_CHALLENGE_TIMEOUT,
    	/// \internal
    	ID_TWO_WAY_AUTHENTICATION_NEGOTIATION,
     
    	/// CloudClient / CloudServer
    	ID_CLOUD_POST_REQUEST,
    	ID_CLOUD_RELEASE_REQUEST,
    	ID_CLOUD_GET_REQUEST,
    	ID_CLOUD_GET_RESPONSE,
    	ID_CLOUD_UNSUBSCRIBE_REQUEST,
    	ID_CLOUD_SERVER_TO_SERVER_COMMAND,
    	ID_CLOUD_SUBSCRIPTION_NOTIFICATION,
     
    	// LibVoice
    	ID_LIB_VOICE,
     
    	ID_RELAY_PLUGIN_TO_RELAY,
    	ID_RELAY_PLUGIN_FROM_RELAY,
     
    	// RelayPlugin::AddParticipantRequestFromClient()
    	ID_RELAY_PLUGIN_ADD_CLIENT,
    	// Result of RelayPlugin::AddParticipantRequestFromClient(). Use bitStream to read one byte, true for success, false for failure (name in use). Use bitStream with ReadCompressed on a RakString to read the original name specified
    	ID_RELAY_PLUGIN_ADD_CLIENT_RESPONSE,
    	ID_RESERVED_3,
    	ID_RESERVED_4,
    	ID_RESERVED_5,
    	ID_RESERVED_6,
    	ID_RESERVED_7,
    	ID_RESERVED_8,
    	ID_RESERVED_9,
     
    	// For the user to use.  Start your first enumeration at this value.
    	ID_USER_PACKET_ENUM
    	//-------------------------------------------------------------------------------------------------------------
     
    };
    La plupart des applications vont n'utiliser qu'une dixaines de ces identifiants, et pas de maniere a ce que les valeurs se suivent. Maintenant admettons que l'on veuille avoir un systeme generique et dynamique qui associe des handlers a l'un de ce ces messages. En gros, on a pas vraiment le choix, on va utiliser un map ou une hash map.


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    typedef std::function<void (Packet)> PacketHandler;
    typedef std::vector<PacketHandler> PacketHandlerList;
     
    std::map< DefaultMessageIDTypes, PacketHandlerList> packet_handler_index;

    Et ce n'est pas si rare que ca. Donc je ne suis pas d'accord avec une generalisation.

  15. #15
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Sauf que, si tu y regarde d'un peu plus près, tu as bel et bien une suite de valeurs entièrement consécutives, et tu as même une valeur qui te permet d'avoir de savoir exactement quelle doit être la taille d'un tableau contenant un élément par valeur énumérée (ID_USER_PACKET_ENUM).

    Ton code pourrait parfaitement tenir sous la forme d'un tableau de PacketHandlerList sans que cela ne porte à conséquence (au contraire, on aurait un accès en O(1) au lieu d'un accès en O(log(n), même si, dans ce cas précis (134 valeurs différentes), le gain n'est pas excessivement important).

    En ne modifiant que le packet_handler_index dans ton code, on pourrait parfaitement avoir un code proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    typedef std::function<void (Packet)> PacketHandler;
    typedef std::vector<PacketHandler> PacketHandlerList;
     
    std::vector<  PacketHandlerList> packet_handler_index(ID_USER_PACKET_ENUM);
    qui aurait exactement le même résultat, à l'exception de la complexité de l'accès aux données

    Tant que tu essayes d'accéder à un des types de messages particulier, tu n'auras aucune différence.

    La seule différence qu'il pourrait éventuellement y avoir, c'est si tu prends la peine de supprimer les éléments qui sont réellement vide (dont PacketHandlerList est vide) et que tu ne veux parcourir que les éléments qui contiennent, effectivement, des packetHandler

    Et même là, un "simple" test du genre de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    for(int i = 0; i< ID_USER_PACKET_ENUM;++i){
        if(!packet_handler_index[i].empty()){
            /*ce qu'il faut faire */
        }
    }
    te permettra de travailler correctement

    Comprend bien que je ne suis pas opposé à l'utilisation de la std::map, et, contrairement à ce que j'ai peut etre laissé paraitre dans ma première intervention, je ne suis pas opposé ni à l'utilisation de valeur numériques ni à celle de valeur énumérées en tant que clé.

    Ce que je dis plutôt, c'est que si tu as de bonnes raisons de penser que les valeurs numérique sont successives et que tu as peu de raison de croire qu'il y a "plus de trous" qu'autre chose, le tableau semble être le meilleur choix parce qu'un fois qu'il a été mis à la bonne taille, l'accès aux éléments se fera de manière plus efficace.
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  16. #16
    Membre expert
    Avatar de Klaim
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Août 2004
    Messages
    1 717
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur de jeux vidéo
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 1 717
    Points : 3 344
    Points
    3 344
    Par défaut
    Citation Envoyé par Klaim Voir le message
    La plupart des applications vont n'utiliser qu'une dixaines de ces identifiants, et pas de maniere a ce que les valeurs se suivent.
    Comme je disais, ca ne marche pas ici parcequ'il y a peu de ces messages qui sont reellement utilise par les applications clientes. Autrement dis, je doute que conseilles d'utiliser un vector en sachant qu'environ 10 des valeurs, eparpillees au milieu du vector, seraient utilisees.

    Je n'ai pas pris cet exemple au hasard, mais bien pour montrer en quoi c'est utile.

    Comprend bien que je ne suis pas opposé à l'utilisation de la std::map, et, contrairement à ce que j'ai peut etre laissé paraitre dans ma première intervention, je ne suis pas opposé ni à l'utilisation de valeur numériques ni à celle de valeur énumérées en tant que clé.

    Ce que je dis plutôt, c'est que si tu as de bonnes raisons de penser que les valeurs numérique sont successives et que tu as peu de raison de croire qu'il y a "plus de trous" qu'autre chose, le tableau semble être le meilleur choix parce qu'un fois qu'il a été mis à la bonne taille, l'accès aux éléments se fera de manière plus efficace.
    Dans ce cas on est d'accord. Il sagit donc du cas ou les valeurs se suivent ET on a besoin de gerer toutes les valeurs dynamiquement (statiquement on pourrait utiliser un switch). Ce n'est donc pas directement lie au fait d'utiliser un enum, meme si c'est un moyen pratique de generer les bonnes conditions, cela peut etre utilise differement.

  17. #17
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Citation Envoyé par Klaim Voir le message
    Comme je disais, ca ne marche pas ici parcequ'il y a peu de ces messages qui sont reellement utilise par les applications clientes. Autrement dis, je doute que conseilles d'utiliser un vector en sachant qu'environ 10 des valeurs, eparpillees au milieu du vector, seraient utilisees.

    Je n'ai pas pris cet exemple au hasard, mais bien pour montrer en quoi c'est utile.
    Hé bien, je comprend parfaitement ce que tu veux dire, mais je dirais encore que cela pourrait très bien dépendre des restriction en terme d'utilisation de mémoire (quoi que meme une centaine de std::vector inutilisé ne fasse pas une *si* grande utilisation de mémoire que ca) et du besoin de performances "brut".

    Quitte, pourquoi pas, à avoir sur le coté un tableau qui contiendrait juste les "index utilisés"

    J'ai croisé il y a quelques mois un bench sur les performances comparées des différentes collections, et si l'on peut se permettre de "perdre" 2ko de mémoire utilisée "indument" mais que le besoin de performances est important, on en revient (sans aller jusqu'à l'optimisation prématurée) toujours à "la bonne structure de donnée pour le bon usage".

    Enfin, là, on entre dans des considérations tout à fait particulières hein
    Dans ce cas on est d'accord. Il sagit donc du cas ou les valeurs se suivent ET on a besoin de gerer toutes les valeurs dynamiquement (statiquement on pourrait utiliser un switch). Ce n'est donc pas directement lie au fait d'utiliser un enum, meme si c'est un moyen pratique de generer les bonnes conditions, cela peut etre utilise differement.
    Non, c'est beaucoup plus lié au fait que la clé peut parfaitement être considéré comme un index, du moins, dans certains contextes, et au fait que les tableaux apportent des garanties bien plus intéressantes que n'importe quelle autre collection dans de telles conditions (parmi lesquelles on compte très certainement les données contiguës en mémoire et l'accès aux éléments en temps constant).
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

Discussions similaires

  1. allocation dans une <map>
    Par elekis dans le forum C++
    Réponses: 3
    Dernier message: 28/09/2005, 22h30
  2. Destruction dans une map
    Par Clad3 dans le forum C++
    Réponses: 3
    Dernier message: 21/08/2005, 08h45
  3. Réponses: 20
    Dernier message: 22/03/2005, 21h07
  4. Inserer des elements dans une map sans rangement ?
    Par Muetdhiver dans le forum C++
    Réponses: 3
    Dernier message: 07/09/2004, 11h09
  5. problème de références _ptr dans une map STL
    Par Mr_Tyu dans le forum CORBA
    Réponses: 1
    Dernier message: 10/08/2004, 10h39

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