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 :

Définition d'un type pour une spécialisation de template


Sujet :

C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Responsable 2D/3D/Jeux


    Avatar de LittleWhite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2008
    Messages
    27 119
    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 119
    Billets dans le blog
    148
    Par défaut Définition d'un type pour une spécialisation de template
    Bonjour à tous,

    Je me demandais, est t-il possible de définir un type, une sorte de type poupée, pour indiquer une définition particulière d'un template ?
    En effet, j'ai le code suivant :
    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
        template <typename T>
        class EaseInEaseOutInterpolation
        {
        protected:
            static T get(const T& begin, const T& end, float interp)
            {
                // http://math.stackexchange.com/questions/121720/ease-in-out-function
                float interp2 = interp*interp;
                return (interp2 / (interp2 + (1 - interp)*(1 - interp))) * (end-begin)+begin;
            }
        };
     
        template <>
        class EaseInEaseOutInterpolation<Angle>
        {
        protected:
            static Angle get(const Angle& begin, const Angle& end, float interp)
            {
                Angle diff = end-begin;
                Angle fixedBegin = begin;
                Angle fixedEnd = end;
                if ( diff > 180 ) // Here, normal interpolation will take the longest path
                {
                    fixedBegin += 360;
                }
                else if ( diff < -180 )
                {
                    fixedEnd += 360;
                }
                Angle result = EaseInEaseOutInterpolation<float>::get(begin,end,interp);
     
                // Wrap angle
                while ( result > 360 )
                {
                    result -= 360.f;
                }
                while ( result < -360 )
                {
                    result += 360.f;
                }
                return result;
            }
        };
    Et "bien sur" j'ai Angle, qui est défini ainsi :
    Lorsque j'exécute le code, j'ai une belle erreur de segmentation. Simple à comprendre : le template spécialisé s'appelle en boucle, car pour lui, que ce soit un Angle, ou un float, c'est exactement la même chose.

    Comment pourrais-je donc vraiment créer un type Angle, qui soit un float, mais qui tombe dans une spécialisation autre, pour le template ?

    Merci
    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.

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Saut,
    Pourquoi ne pas, simplement, faire un trait ?
    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
    struct Angle{
        using value_type  = float;
        value_type value;
    };
    template <typename T>
        class EaseInEaseOutInterpolation
        {
        protected:
            static T get(const T& begin, const T& end, float interp)
            {
                // http://math.stackexchange.com/questions/121720/ease-in-out-function
                float interp2 = interp*interp;
                return (interp2 / (interp2 + (1 - interp)*(1 - interp))) * (end-begin)+begin;
            }
        };
    class EaseInEaseOutInterpolation<Angle>
        {
        protected:
            static Angle get(const Angle& begin, const Angle& end, float interp)
            {
                Angle::value_type diff = end.value-begin.value;
                Angle::value_type fixedBegin = begin.value;
                Angle::value_type fixedEnd = end.value;
                if ( diff > 180 ) // Here, normal interpolation will take the longest path
                {
                    fixedBegin += 360;
                }
                else if ( diff < -180 )
                {
                    fixedEnd += 360;
                }
                Angle result = EaseInEaseOutInterpolation<Angle::value_type>::get(begin.value,end.value,interp);
     
                // Wrap angle
                while ( result > 360 )
                {
                    result -= 360.f;
                }
                while ( result < -360 )
                {
                    result += 360.f;
                }
                return result;
            }
        };
    (code non testé, mais l'idée y est ) Et, en C++11, tu devrais même pouvoir te permettre de jouer avec std::enable_if pour n'avoir pas à recopier toute la classe

    EDIT d'ailleurs, en y pensant, en créant deux traits similaires (DegAngle et RadAngle), tu devrais même pouvoir envisager d'avoir des angles représentés en degré (minutes / secondes) et en radians
    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

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


    Avatar de LittleWhite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2008
    Messages
    27 119
    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 119
    Billets dans le blog
    148
    Par défaut
    Pourquoi, simplement car je ne suis pas habitué avec ce concept.
    De plus, je n'aime pas le fait qu'il faille écrire : Angle::value_type et non pouvoir utiliser Angle directement
    Je suis en C++11 \ o /, je vais donc voir pour le std::enable_if.
    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.

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Citation Envoyé par LittleWhite Voir le message
    Pourquoi, simplement car je ne suis pas habitué avec ce concept.
    Tu devrais vraiment essayer de t'habituer à ce concept... Les traits et les politiques sont sans aucun doute les deux concepts les plus importants que l'on trouve dans la STL
    De plus, je n'aime pas le fait qu'il faille écrire : Angle::value_type et non pouvoir utiliser Angle directement
    Oh, si tu veux, tu peux envisager d'avoir un opérateur de conversion implicite ... Mais, le fait est que, d'une manière ou d'une autre, tu va systématiquement limiter le type sous-jacent à un typedef. Si tu veux pouvoir connaitre ce type sous-jacent, il n'y a pas énormément de possibilité : tu dois t'assurer de disposer d'un identificateur susceptible de s'adapter à ce type

    N'oublies pas que le typedef (ou la directive using, en C++11) ne fait que créer un alias de type. Quand tu écris le code typedef float Angle, tu ne fais que dire au compilateur qu'il doit remplacer les différentes occurrences du terme Angle par le type réel float dans le code. Ton problème vient du fait qu'il ne sait donc pas faire la différence entre les deux
    Note que tu pourrais très bien modifier un tout petit peu le code pour lui donner 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
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    struct Angle{
        using value_type  = float;
        value_type value;
    };
    class EaseInEaseOutInterpolation<Angle>
        {
        using value_type = Angle::value_type;
        protected:
            static Angle get(const Angle& begin, const Angle& end, float interp)
            {
                // http://stackoverflow.com/questions/2708476/rotation-interpolation
                value_type diff = end.value-begin.value;
                value_type fixedBegin = begin.value;
                value_type fixedEnd = end.value;
                if ( diff > 180 ) // Here, normal interpolation will take the longest path
                {
                    fixedBegin += 360;
                }
                else if ( diff < -180 )
                {
                    fixedEnd += 360;
                }
                Angle result = EaseInEaseOutInterpolation<Angle::value_type>::get(begin.value,end.value,interp);
     
                // Wrap angle
                while ( result > 360 )
                {
                    result -= 360.f;
                }
                while ( result < -360 )
                {
                    result += 360.f;
                }
                return result;
            }
        };
    Et, d'ailleurs, à bien y réflechir, nous pourrions même aller encore plus loin et décider de donner au code 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
    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
    template <typename T>
    class Angle{
        using value_type = T;
        value_type value;
        Angle(value_type v):value(v){}
    }
    /* Quand on utilise les types primitifs */
    template <typename T, typename Trait = T>
    class EaseInEaseOutInterpolation{
     
        protected:
            static T get(const T& begin, const T& end, float interp)
            {
                // http://math.stackexchange.com/questions/121720/ease-in-out-function
                float interp2 = interp*interp;
                return (interp2 / (interp2 + (1 - interp)*(1 - interp))) * (end-begin)+begin;
            }
    };
     
    /* Quand on utilise les traits */
    template <typename T>
    class EaseInEaseOutInterpolation<T, Angle<T>> {
    using angle_type = Angle<T>;
    using value_type = Angle<T>::value_type;
        protected:
            static angle_type get(const angle_type& begin, const angle_type& end, T interp)
            {
                // http://stackoverflow.com/questions/2708476/rotation-interpolation
                angle_type diff = end.value-begin.value;
                value_type fixedBegin = begin.value;
                value_type fixedEnd = end.value;
                if ( diff > 180 ) // Here, normal interpolation will take the longest path
                {
                    fixedBegin += 360;
                }
                else if ( diff < -180 )
                {
                    fixedEnd += 360;
                }
                angle_type result = EaseInEaseOutInterpolation<value_type>::get(begin.value,end.value,interp);
     
                // Wrap angle
                while ( result > 360 )
                {
                    result -= 360.f;
                }
                while ( result < -360 )
                {
                    result += 360.f;
                }
                return result;
            }
    };
    Je suis en C++11 \ o /, je vais donc voir pour le std::enable_if.
    Attention : enable_if ne te permettra pas d'éviter le recours à un trait et à une politique... Tout ce que enable_if pourra faire pour toi est d'éviter d'avoir à définir une version générique et une version (partiellement) spécialisée de ta classe EaseInEaseOutInterpolation
    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
    Responsable 2D/3D/Jeux


    Avatar de LittleWhite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2008
    Messages
    27 119
    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 119
    Billets dans le blog
    148
    Par défaut
    Tu devrais vraiment essayer de t'habituer à ce concept... Les traits et les politiques sont sans aucun doute les deux concepts les plus importants que l'on trouve dans la STL
    J'en suis pleinement conscient et c'est pour ça que je ne vous ai pas demandé ce qu'était un trait. Par contre, même si ont les trouvent partout dans la STL, cela ne veut pas dire qu'ils sont importants. On est pas obligé de comprendre comment la STL est implémenté

    Attention : enable_if ne te permettra pas d'éviter le recours à un trait et à une politique... Tout ce que enable_if pourra faire pour toi est d'éviter d'avoir à définir une version générique et une version (partiellement) spécialisée de ta classe EaseInEaseOutInterpolation
    Je l'avais compris aussi.

    Mon problème avec Angle, c'est que c'est un type, qui peut être visible pour l'utilisateur et, utilisé par l'utilisateur. Du coup, même si j'évite de taper des Angle::value_type dans le template, si l'utilisateur l'utilise, il le devra.
    Ce qui me gêne encore plus, c'est que vous ne pouvez pas faire Angle = Angle + Angle, vous êtes obligé de piocher au sein de la structure (soit, faire Angle::value_type). Cela ne semble pas logique que Angle, devienne une classe et que je ne peux pas ajouter (faire des opérations arithmétique) avec des Angle, directement.

    Par contre, on peut juste utiliser les Angle en interne (dans le template) et faire en sorte que l'utilisateur ne voit jamais ce Angle, et juste l'utilisé ainsi :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    EaseInEaseOutInterpolation<Angle>::get(begin,end,t)
    begin et end pouvant être des float qui se feront convertir à la volée, implicitement. Mais du coup, comment cacher complètement Angle, pour que l'utilisateur ne puisse pas l'utiliser comme type, mais uniquement comme trait pour le template.
    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.

  6. #6
    Expert éminent

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 202
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

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

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 202
    Par défaut
    Le problème est que typedef ne crée pas un vrai type, et using non plus. Avec eux, Angle est float.
    C'est le même type, il n'y a qu'une spécialisation.

    Du coup, une autre approche possible, c'est le wrapper "souple", une classe qui se traduise facilement en float, sans aucun secret.

    Par exemple, quelque chose proche de ceci:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    class Angle {
    private:
        float value;
     
    public:
        Angle(float f=0): value(f) {}
        operator float() const {return value;}
        operator float&() {return value;}//c'est possible, ca?
        Angle& operator =(float f) {value = f; return *this;}
    };

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

Discussions similaires

  1. Content-type pour une pièce jointe dans un mail
    Par rcjcrcjc dans le forum Langage
    Réponses: 2
    Dernier message: 14/10/2009, 18h51
  2. confilcting types pour une structure ?
    Par Tymk dans le forum C
    Réponses: 5
    Dernier message: 03/07/2008, 08h59
  3. type pour une matrice cubique d'entiers
    Par italiasky dans le forum C
    Réponses: 4
    Dernier message: 26/06/2007, 21h49
  4. quel est le type pour une image?
    Par kitiara999 dans le forum SQL Procédural
    Réponses: 3
    Dernier message: 06/12/2006, 18h07
  5. [TYPE DE CHAMPS] Quel type pour une primary key ?
    Par guy2004 dans le forum SQL Procédural
    Réponses: 4
    Dernier message: 25/03/2006, 12h23

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