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 :

Existe-t-il un typedef "fort"?


Sujet :

C++

  1. #1
    Membre du Club
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Juin 2006
    Messages
    122
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

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

    Informations forums :
    Inscription : Juin 2006
    Messages : 122
    Points : 59
    Points
    59
    Par défaut Existe-t-il un typedef "fort"?
    Holla.

    Question énigmatique j'en conviens.

    J'aimerais savoir si il y a moyen de definir un type def comme "fort". Je ne connais pas le mot qui va bien, alors exemple :

    Si je fais.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    typedef unsigned int Identifiant;
    Lorsque je veux faire les deux declaration de fonction suivantes :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    void fonction(unsigned int id);
    void fonction(Identifiant id);
    Il va me mettre une erreur "fonction deja definie".

    Comment faire pour qu'il prenne le type Identifiant comme un type a part entier et non un synonyme du unsigned int?

    Une solution serait de faire un struct :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    struct Identifiant
    {
    	unsigned int value;
    };
    Mais ca me demanderais a redefinir tout les operateurs juste pour ca, fastidieux. Y a-t-il un moyen plus ingenieux de le faire?

  2. #2
    En attente de confirmation mail

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2004
    Messages
    1 391
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France, Doubs (Franche Comté)

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

    Informations forums :
    Inscription : Août 2004
    Messages : 1 391
    Points : 3 311
    Points
    3 311
    Par défaut
    Bonsoir,

    Un typedef ne déclare pas un type, c'est juste un autre nom pour un type déjà existant. De la même manière qu'une référence n'est qu'un autre nom pour un objet déjà existant et pas un nouvel objet.

    On pourrait templater une structure qui encapsule un objet d'un type et jouer avec un "Dummy" type et un opérateur de conversion implicite pour faire ca.

    Cependant l'interet m'échappe un peu :
    -> Toutes ses classes auront la même sémantique (*)
    -> Des fonctions offrant des fonctionnalitées identiques (même noms) dans un même contexte (même scope) auront des comportements différents.

    Or cette différence va se faire sur le type des objets, et donc leur sémantique, ie une différence est introduite alors que rien ne la justifie.

    Tu aurais un exemple de l'utilité d'un tel mécanisme ?

    (*) C'est cette hyptohèse qui est peut-être fausse, mais dans ce cas c'est que tu as pensé ta conception en terme de données et non de responsabilité : peut importe qu'en interne les données à manipuler soient des entiers, deux objet doivent avoir deux responsabilités différentes, alors deux classes bien distinctes qui offrent chacunes une interface propre est une solution viable.

  3. #3
    Membre du Club
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Juin 2006
    Messages
    122
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

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

    Informations forums :
    Inscription : Juin 2006
    Messages : 122
    Points : 59
    Points
    59
    Par défaut
    Je vais essayer d'expliquer ma situation. Tout est a l'etat de design, donc rien de defini, d'ou ma question.

    Je me fait un editeur de jeu, et pour pouvoir construire le gameplay du jeu, je me lance dans un system de Graph, qui va permettre de construire un comportement a l'aide de boite a relier entre elles. Parmis ces boites, certaines sont des liens vers les differentes variables de mes objets, donc la position, les points de vie, mais aussi les ressources (images, sons, sprite) et d'autres objets.

    Et c'est justement ces autres ressource qui me pose probleme. Je veux rendre ce system de graph le moins permissif possible, donc faire en sorte que lorsqu'une boite attend de recevoir une image, on lui colle pas un son ou un entier. Or, les ressources sont accessible via un simple identifiant, de meme pour les objets, et ces identifiant sont justement de simple short.

    J'ai fais une classe variable qui contiens le pointeur vers l'objet (int, short, etc) et un enumerateur Type, pour savoir explicitement quel type la variable renvois vers, et surtout quelle type elle attend, ce qui va me permettre d'indiquer effectivement ce qu'on doit lui affecter comme valeur : un entier, un string, ou identifiant de ressource, un identifiant d'objet, etc.

    Et c'est lorsque je passe le pointeur de mon objet C que j'ai besoin de differencier si j'utilise un Id d'objet ou un type C.

    Je pourrais faire simplement un SetId ou un GetId, en + des Get et Set que j'ai fais pour les type C, mais je veux rendre mes fonctions "harmonizees". :p

    Voila, j'espere que j'ai ete clair, il est tard et j'ai faim a l'heure ou j'ecris.

  4. #4
    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,

    En fait, ce que tu veux faire, c'est placer des pré / post conditions lors de la création de ton graphe...

    Ce n'est donc pas au graphe lui-même de veiller à ce que la pré condition (qui veut qu'un objet attende une image ou un entier comme ressource) soit remplie, mais bien... à "ce qui va générer l'objet".

    Ce que tu peux donc faire, c'est faire en sorte:
    1. qu'il existe une classe dérivée par type de ressource à manipuler
    2. que ce soit cette classe dérivée qui contienne un pointeur vers le type réel de la ressource qu'elle manipule
    Tu pourrais donc parfaitement mettre en place un système de "type erasure" proche de
    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
     
    class AbstractNode
    {
        public:
            /* l'interface propre au noeud du graphe en lui-même +
             * une fonction virtuelle pure permettant de brancher un 
             * visiteur sur l'objet
             */
           virtual void accept(Visitor const & v) /* const */ = 0;
    };
    template <typename RES>
    class RealNode : public AbstractNode
    {
        public:
            typedef RES Ressource;
            typedef RES * ResPtr;
            RealNode(ResPtr ressource):ressource_(ressource){}
            virtual void accept(Visitor const & v)/* const */{v.visit(*this);}
            void connectRessource(ResPtr res)
            {
                assert(!ressource_); // PRE : il ne peut pas y avoir de ressource deja connectée
                ressource_ = res;
            }
            void disconnectRessource()
            {
                ressource_ = NULL; /* nullptr en C++11 */
            }
        private:
            ResPtr ressource_;
    };
    Le visiteur prendrait une forme proche de
    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
    class Visitor
    {
        public:
            void visit(AbstractNode * visitable)
            {
                visitable->accept(*this);
            }
            /* pour chaque type de noeud réel */
            /* virtual */ void visit(RealNode<Image> /* const & rn) /* const */
            {
                /* ce qu'il faut faire */
            } 
            /* virtual */ void visit(RealNode<Sound> /* const & rn)/* const */
            {
                /* ce qu'il faut faire */
            } 
     
            /* virtual */ void visit(RealNode<int> /* const & rn)/* const */
            {
                /* ce qu'il faut faire */
            } 
    };
    Et tu pourrais même avoir une fabrique qui, en écrivant une seule fonction template te permettrait de fabriquer tous tes noeuds :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    class Factory
    {
        template typename <RES>
        AbstractNode * create(RES * ressource)
        {
            AbstractNode * temp = new RealNode<RES>(ressource);
            /* les actions "connexes" */
            return temp;
        }
    };
    Enfin, pour pouvoir vérifier plus facilement le type attendu par les différents noeuds, tu aurais sans doute ton énumération qui prendrait une forme proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    enum RType
    {
        RType_Integer,
        RType_Sound,
        RType_Image /* ,
         ...*/
    };
    pour laquelle tu créerait un trait de politique proche de
    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
    template <typename >
    struct RessourceTrait;
    template <>
    struct RessourceTrait<RessourceImage>
    {
        enum {type = RType_Image};
    };
    template <>
    struct RessourceTrait<RessourceInteger>
    {
        enum {type = RType_Integer};
    };
    template <>
    struct RessourceTrait<RessourceSound>
    {
        enum {type = RType_Sound};
    };
    /* ...*/
    et qui s'intégrerait dans RealNode sous une forme proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    template <typename RES>
    class RealNode : public AbstractNode
    {
        public:
        enum {type = RessourceTrait<RES>::type};
        /* comme précédemment */
    };
    et un de tes visiteurs pourrait alors s'assurer que rn::type correspond bien à la valeur qu'il a récupérée par ailleurs
    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

  5. #5
    Membre chevronné
    Avatar de Joel F
    Homme Profil pro
    Chercheur en informatique
    Inscrit en
    Septembre 2002
    Messages
    918
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Chercheur en informatique
    Secteur : Service public

    Informations forums :
    Inscription : Septembre 2002
    Messages : 918
    Points : 1 921
    Points
    1 921
    Par défaut
    Boost.Serialization propose la macro BOOST_STRONG_TYPEDEF pour cela

  6. #6
    Membre émérite
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    2 764
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 2 764
    Points : 2 705
    Points
    2 705
    Par défaut
    Citation Envoyé par Flob90 Voir le message
    On pourrait templater une structure qui encapsule un objet d'un type et jouer avec un "Dummy" type et un opérateur de conversion implicite pour faire ça.

    Cependant l'interet m'échappe un peu :
    -> Toutes ses classes auront la même sémantique (*)
    -> Des fonctions offrant des fonctionnalitées identiques (même noms) dans un même contexte (même scope) auront des comportements différents.

    Or cette différence va se faire sur le type des objets, et donc leur sémantique, ie une différence est introduite alors que rien ne la justifie.

    Tu aurais un exemple de l'utilité d'un tel mécanisme ?

    (*) C'est cette hyptohèse qui est peut-être fausse, mais dans ce cas c'est que tu as pensé ta conception en terme de données et non de responsabilité : peut importe qu'en interne les données à manipuler soient des entiers, deux objet doivent avoir deux responsabilités différentes, alors deux classes bien distinctes qui offrent chacunes une interface propre est une solution viable.
    Cela peut être utile pour gérer des unités physiques, et on n'a pas forcément besoin pour cela de créer une classe et une interface. Une masse et une distance sont deux réels, donc de même type, mais on ne veut pas être en mesure de les additionner.

  7. #7
    Membre régulier
    Profil pro
    Inscrit en
    Avril 2008
    Messages
    87
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Avril 2008
    Messages : 87
    Points : 111
    Points
    111
    Par défaut
    Cela peut être utile pour gérer des unités physiques, et on n'a pas forcément besoin pour cela de créer une classe et une interface. Une masse et une distance sont deux réels, donc de même type, mais on ne veut pas être en mesure de les additionner.
    tout a fait, et il y a d'ailleurs tout un bouquin a ce propos il me semble. en tout cas au moins un papier.

    il n'y a pas que ca, il y a aussi les IDs, un ID d'arbre n'est pas un ID de texture par exemple. pourtant c'est juste des entiers. moi je les encapsulent dans des structures differentes. (apres qui peuvent avoir un template si on veut, et meme une base)

    j'avais eu le meme souci pour des indices de keyframes fortes ou absolues.
    (une non forte est une soeur de forte, utile pour marquer l'arret d'un effet)
    j'ai du faire des structures avec des fonctions de conversions pourtant au final c'est juste un size_t encapsulé. mais ils ne doivent pas etre entre assignables.

  8. #8
    Membre émérite
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    2 764
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 2 764
    Points : 2 705
    Points
    2 705
    Par défaut
    Citation Envoyé par Lightness1024 Voir le message
    tout a fait, et il y a d'ailleurs tout un bouquin a ce propos il me semble. en tout cas au moins un papier.
    Et en tout cas une bibliothèque (pas que pour cette problématique, je l'accorde) : Boost MPL.

  9. #9
    En attente de confirmation mail

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2004
    Messages
    1 391
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France, Doubs (Franche Comté)

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

    Informations forums :
    Inscription : Août 2004
    Messages : 1 391
    Points : 3 311
    Points
    3 311
    Par défaut
    @oodini: Solution tiré du bouquin d'Abrahams :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    template<class T, class Dimension>
    struct quantity
    {
      explicit quantity(T x) : m_value(v) {}
      T value() const { return m_value; }
    private:
      T m_value;
    };
    Il définit une classe (template) et une interface. Chaque classe instanciée contiendra une information différente sur sa dimension qui praticipe à ca sémantique : aucune des classes n'a la même sémantique, les traiter différement est justifié.

  10. #10
    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
    Et quand on regarde la solution proposée par Boost, c'est exactement ça également.
    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.

  11. #11
    Membre du Club
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Juin 2006
    Messages
    122
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

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

    Informations forums :
    Inscription : Juin 2006
    Messages : 122
    Points : 59
    Points
    59
    Par défaut
    Citation Envoyé par Joel F Voir le message
    Boost.Serialization propose la macro BOOST_STRONG_TYPEDEF pour cela
    C'est grosso merdo ce qu'il me fallait. :p

    J'ai utilise le terme de graph, mais c'est plus complique qu'un simple graph. Ce n'est pas l'interaction entre node qui me pose soucis, c'est les variables que je veux "connecter" aux nodes le probleme.

    Bon je dois avouer que je n'ai pas compris 50% de tout ce que vous avez dis au dessus, je suis pas encore assez familier avec les termes de programmation.

    Pour les exemple de code, j'utilise deja ce genre de fonctionnement pour mes Nodes, mais vu que ce n'est pas les nodes en elles meme le probleme...

    M'enfin merci pour toutes vos reponses. :]

  12. #12
    Expert confirmé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Décembre 2003
    Messages
    3 549
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

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

    Informations forums :
    Inscription : Décembre 2003
    Messages : 3 549
    Points : 4 625
    Points
    4 625
    Par défaut
    BOOST_STRONG_TYPEDEF est imparfait. Avec C++11 il y a de meilleures méthodes de faire un typedef fort.

    Mais bon si tu n'en as besoin que ponctuellement autant faire un truc ad-hoc adapté à ton cas.
    Boost ftw

  13. #13
    Membre du Club
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Juin 2006
    Messages
    122
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

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

    Informations forums :
    Inscription : Juin 2006
    Messages : 122
    Points : 59
    Points
    59
    Par défaut
    En quoi BOOST_STRONG_TYPEDEF est imparfait?

    Je l'utilise pour l'instant, ca n'a pas l'air de poser probleme.

+ Répondre à la discussion
Cette discussion est résolue.

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