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++

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


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

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

    Informations forums :
    Inscription : Mai 2008
    Messages : 26 855
    Points : 218 548
    Points
    218 548
    Billets dans le blog
    118
    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 sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 612
    Points : 30 612
    Points
    30 612
    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
    26 855
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

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

    Informations forums :
    Inscription : Mai 2008
    Messages : 26 855
    Points : 218 548
    Points
    218 548
    Billets dans le blog
    118
    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 sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 612
    Points : 30 612
    Points
    30 612
    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
    26 855
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

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

    Informations forums :
    Inscription : Mai 2008
    Messages : 26 855
    Points : 218 548
    Points
    218 548
    Billets dans le blog
    118
    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 sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 188
    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 188
    Points : 17 136
    Points
    17 136
    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;}
    };
    Mes principes de bases du codeur qui veut pouvoir dormir:
    • Une variable de moins est une source d'erreur en moins.
    • Un pointeur de moins est une montagne d'erreurs en moins.
    • Un copier-coller, ça doit se justifier... Deux, c'est un de trop.
    • jamais signifie "sauf si j'ai passé trois jours à prouver que je peux".
    • La plus sotte des questions est celle qu'on ne pose pas.
    Pour faire des graphes, essayez yEd.
    le ter nel est le titre porté par un de mes personnages de jeu de rôle

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


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

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

    Informations forums :
    Inscription : Mai 2008
    Messages : 26 855
    Points : 218 548
    Points
    218 548
    Billets dans le blog
    118
    Par défaut
    Oui, je suis totalement d'accord leternel. C'est à un moment, la solution que j'ai envisagé.
    Mais il reste que je trouvais cela "lourd".

    Pour la solution de koala01 :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    using value_type = Angle<T>::value_type;
    ne passe pas ->
    expected type-specifier
    Si je le feinte (en utilisant T, directement), j'ai le même problème, lors de l'utilisation du template d'interpolation, pour la même raison, comme quoi le type Math::Angle passé au template n'est pas un type, alors qu'il attend un type.

    Pour le std::enable_if, en lisant la documentation (cppreference), je ne saurais pas l'utiliser et y voir son avantage (du moins, pas dans ce cas).
    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.

  8. #8
    Membre expert
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2011
    Messages
    739
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

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

    Informations forums :
    Inscription : Juin 2011
    Messages : 739
    Points : 3 627
    Points
    3 627
    Par défaut
    Citation Envoyé par LittleWhite Voir le message
    Pour la solution de koala01 :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    using value_type = Angle<T>::value_type;
    ne passe page ->
    il manque un typename : using value_type = typename Angle<T>::value_type;.

    Sinon, pourquoi ne pas faire une fonction get_impl() en protégé dans le classe de base ? Ainsi, toutes les spécialisation ayant besoin de get() utiliseront get_impl(). Mais cela causes des problèmes si plusieurs spécialisation sont chaînées...

    Sinon avec une autre forme de 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
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    template <typename T>
    struct EaseInEaseOutInterpolation;
     
    template <typename T>
    struct EaseInEaseOutInterpolationDispatch
    {
      // http://math.stackexchange.com/questions/121720/ease-in-out-function
      static T get(const T& begin, const T& end, float interp)
      {
        float interp2 = interp*interp;
        return (interp2 / (interp2 + (1 - interp)*(1 - interp))) * (end-begin)+begin;
      }
     
    protected:
      template<class U>
      using impl = typename std::conditional<
        std::is_same<T, U>::value
      , EaseInEaseOutInterpolationDispatch
      , EaseInEaseOutInterpolation<T>
      >::type;
    };
     
    template <typename T>
    struct EaseInEaseOutInterpolation
    {
    protected:
      static T get(const T& begin, const T& end, float interp)
      {
        return EaseInEaseOutInterpolationDispatch<T>::template impl<T>::get(begin, end, interp);
      }
    };
     
     
    template <>
    struct EaseInEaseOutInterpolation<Angle>
    : protected EaseInEaseOutInterpolationDispatch<Angle>
    {
    protected:
      static Angle get(const Angle& begin, const Angle& end, float interp)
      {
        // http://stackoverflow.com/questions/2708476/rotation-interpolation
        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 = EaseInEaseOutInterpolationDispatch<Angle>::impl<float>::get(begin,end,interp);
     
        // Wrap angle
        while ( result > 360 )
        {
          result -= 360.f;
        }
        while ( result < -360 )
        {
          result += 360.f;
        }
        return result;
      }
    };

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


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

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

    Informations forums :
    Inscription : Mai 2008
    Messages : 26 855
    Points : 218 548
    Points
    218 548
    Billets dans le blog
    118
    Par défaut
    Votre solution peut être juste, je ne saurai le dire. Pourquoi pas prendre une telle solution ? Car je ne comprends pas correctement le code et je trouve que l'on perd de plus en plus en clarté.
    Notez aussi, que la classe que je vous ai présenté dans le premier message, est en réalité, une classe de politique. Il y a d'autres types d'interpolation dans mon code, est déjà une classe de base, qui va appeler le get de la bonne politique.
    Vous souhaitez participer à la rubrique 2D/3D/Jeux ? Contactez-moi

    Ma page sur DVP
    Mon Portfolio

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

  10. #10
    Membre émérite
    Avatar de white_tentacle
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    1 505
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 1 505
    Points : 2 799
    Points
    2 799
    Par défaut
    Je repars du problème initial. Es-tu sûr que de vouloir arrêter la récursion par le type soit une bonne idée ?

    J’ai plutôt l’impression que dans le cas de Angle, tu fais une passe supplémentaire, et que dans les autres cas, tu appliques directement le template initial. En tout cas, ce qui est certain c’est que dans ce que tu as écrit, tu initialises des Angle, puis essaie d’appeler explicitement une spécialisation pour float qui en réalité n’existe pas, le tout sans même caster tes paramètres, bref, pas bien .

    De mon point de vue, je renommerai simplement le premier EaseInEaseOutInterpolation en EaseInEaseOutInterpolation_internal, et j’appellerai celui-là dans le EaseInEaseOutInterpolation de Angle. Et pour les non-Angle, je définirai un EaseInEaseOutInterpolation qui se contente de faire un appel tel quel à EaseInEaseOutInterpolation_internal. Quelque chose du genre*:

    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
     
     
        template <typename T>
        class EaseInEaseOutInterpolation_internal
        {
        public:
            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<typename T>
        class EaseInEaseOutInterpolation {
        protected: // pourquoi protected ? Je le laisse parce que tu l’as mis, mais bon…
            static T get(const T& begin, const T& end, float interp)
            {
                return EaseInEaseOutInterpolation_internal(begin, end, interp);
            }
        }
        template <>
        class EaseInEaseOutInterpolation<Angle>
        {
        protected:
            static Angle get(const Angle& begin, const Angle& end, float interp)
            {
                // http://stackoverflow.com/questions/2708476/rotation-interpolation
                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_internal::get(begin,end,interp);
     
                // Wrap angle
                while ( result > 360 )
                {
                    result -= 360.f;
                }
                while ( result < -360 )
                {
                    result += 360.f;
                }
                return result;
            }
        };

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


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

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

    Informations forums :
    Inscription : Mai 2008
    Messages : 26 855
    Points : 218 548
    Points
    218 548
    Billets dans le blog
    118
    Par défaut
    Ok white_tentacle mais comment définissez vous "Angle" ? Sachant que le typedef simple n'ira pas, si j'ai bien compris, car si j'utilise des float, le compilateur choisira toujours la spécialisation.
    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.

  12. #12
    Membre émérite
    Avatar de white_tentacle
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    1 505
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 1 505
    Points : 2 799
    Points
    2 799
    Par défaut
    Citation Envoyé par LittleWhite Voir le message
    Ok white_tentacle mais comment définissez vous "Angle" ? Sachant que le typedef simple n'ira pas, si j'ai bien compris, car si j'utilise des float, le compilateur choisira toujours la spécialisation.
    Le problème, c’est qu’il ne faut pas que la spécialisation soit appelée pour des floats « standards », c’est bien ça ?

    Je pense que le fond du problème, c’est dans la définition de Angle. le typedef de Angle vers float me semble une mauvaise idée.

    Si je comprends bien ta définition de Angle, c’est un flottant, dont la valeur est toujours dans l’intervalle [0-360[, et qui fait un modulo pour retomber sur sa valeur à peu près partout où tu t’en sers.

    Bon, partant de là, typedef n’est pas une bonne solution pour garantir ça. Donc je passerai par une abstraction. Quelque chose comme :

    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
     
    class Angle {
    private:
        float value;
    public:
        explicit float operator() { 
            if(value < 0 || value >= 360)
                normalize_value();
            return value;
        }
     
        Angle(float value);
        Angle(Angle const& other);
     
        static Angle operator+(Angle a1, Angle a2);
        // etc...
    }
    Certes, ça fait du code en plus. Mais tu as aussi des bénéfices avec ce code :
    - ton type devient métier, pas seulement un typedef. Et tu y as associé un contrat : la valeur ne peut plus jamais être en dehors de l’intervalle des valeurs possibles.
    - si vraiment tu as beaucoup de types de ce genre, je pense qu’il est possible de faire un type générique « modulo », de manière template (en tout cas avec des bornes entières, ça doit se faire sans soucis).

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


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

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

    Informations forums :
    Inscription : Mai 2008
    Messages : 26 855
    Points : 218 548
    Points
    218 548
    Billets dans le blog
    118
    Par défaut
    Le problème, c’est qu’il ne faut pas que la spécialisation soit appelée pour des floats « standards », c’est bien ça ?
    Oui. Mais mon "Angle", il pourrait aussi bien être un "entier" (pourquoi pas), donc faudra qu'il soit template (mais disons, pour l'instant, on ne se préocupe pas de ce cas ).

    Pour la classe métier Angle, j'y ai pensé, mais je n'arrive pas à savoir à l'avance, si le fait de restreindre les valeurs entre 0 et 360 va planter le reste de mes calculs, ou non.
    De plus, est t-il réellement nécessaire de définir un nouveau type, complètement ?
    Vous souhaitez participer à la rubrique 2D/3D/Jeux ? Contactez-moi

    Ma page sur DVP
    Mon Portfolio

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

  14. #14
    Membre émérite
    Avatar de white_tentacle
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    1 505
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 1 505
    Points : 2 799
    Points
    2 799
    Par défaut
    Citation Envoyé par LittleWhite Voir le message
    Pour la classe métier Angle, j'y ai pensé, mais je n'arrive pas à savoir à l'avance, si le fait de restreindre les valeurs entre 0 et 360 va planter le reste de mes calculs, ou non.
    Aucune idée. Par contre, tu peux te permettre de ne faire le modulo qu’à la conversion en float. Si tu redéfinis toutes les opérations usuelles sur ton Angle, cela devrait te permettre de garder la valeur hors intervalle le plus longtemps possible, et de ne la normaliser qu’à la fin. Ça peut être important pour les perfs, mais aussi pour la précision du calcul puisqu’on parle de flottants.

    De plus, est t-il réellement nécessaire de définir un nouveau type, complètement ?
    Le contrat est différent, le comportement est différent. Donc oui, nouveau type.

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


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

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

    Informations forums :
    Inscription : Mai 2008
    Messages : 26 855
    Points : 218 548
    Points
    218 548
    Billets dans le blog
    118
    Par défaut
    En conclusion, j'ai créé un nouveau type Angle. J'ai spécialisé mon template par rapport à ce nouveau type et j'ai fait en sorte, que son utilisation soit la plus transparente possible pour l'utilisateur.
    Merci pour vos pistes
    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.

  16. #16
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 188
    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 188
    Points : 17 136
    Points
    17 136
    Par défaut
    Du coup, ca donne quoi?
    Mes principes de bases du codeur qui veut pouvoir dormir:
    • Une variable de moins est une source d'erreur en moins.
    • Un pointeur de moins est une montagne d'erreurs en moins.
    • Un copier-coller, ça doit se justifier... Deux, c'est un de trop.
    • jamais signifie "sauf si j'ai passé trois jours à prouver que je peux".
    • La plus sotte des questions est celle qu'on ne pose pas.
    Pour faire des graphes, essayez yEd.
    le ter nel est le titre porté par un de mes personnages de jeu de rôle

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


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

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

    Informations forums :
    Inscription : Mai 2008
    Messages : 26 855
    Points : 218 548
    Points
    218 548
    Billets dans le blog
    118
    Par défaut
    Un type Angle :
    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
    namespace Math
    {
        template <typename T>
        struct Angle
        {
            T value;
     
            Angle(const T& value):value(value) {}
            operator float()const { return this->value; }
     
            void wrap()
            {
                while ( this->value > 360 )
                {
                    this->value -= 360;
                }
                while ( this->value < -360 )
                {
                    this->value += 360;
                }
            }
        };
    }
    (On pourrait chercher à faire un peu plus)

    Et le template classique :
    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
    template <typename T>
        class EaseInEaseOutInterpolation<Angle<T> >
        {
        public:
            static Angle<T> get(const Angle<T>& begin, const Angle<T>& end, float interp)
            {
                // http://stackoverflow.com/questions/2708476/rotation-interpolation
                T diff = end.value-begin.value;
                T fixedBegin = begin.value;
                T fixedEnd = end.value;
                if ( diff > 180 ) // Here, normal interpolation will take the longest path
                {
                    fixedBegin += 360;
                }
                else if ( diff < -180 )
                {
                    fixedEnd += 360;
                }
                Angle<T> result = EaseInEaseOutInterpolation<float>::get(fixedBegin,fixedEnd,interp);
                result.wrap();
                return result;
            }
        };
    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.

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 612
    Points : 30 612
    Points
    30 612
    Par défaut
    J'ai quand même deux question à te poser...

    La première te paraîtra peut être idiote, mais, pourquoi avoir créer float operator() au lieu de T operator() Cette question en implique quelques autres comme :
    • As-tu envisagé le fait que ta classe angle est template et que l'on peut donc avoir un développeur qui décidera de l'utiliser avec un paramètre template de type entier ou (plus embêtant) avec un paramètre template de type réel mais présentant une précision supérieure (comme double ou long double)
    • Ce genre de conversion ne risque-t-il pas, d'une manière ou d'une autre de provoquer une perte de précision préjudiciable à la précision obtenue

    La deuxième a simplement trait à la logique utilisée pour la fonction wrap. Ta logique n'est pas mauvaise en soi, mais je me demande réellement s'il n'y aurait pas moyen de la simplifier en utiliseant le modulo, sous 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
    template <typename T>
    void Angle<T>::wrap(){
        this->value %=360; // j'ai un doute : this est-il indispensable ici???
        //-762 % 360 == -42  == 318 == 360 - 42 ;)
        /* on pourrait peut etre profiter du fait que l'opérateur ternaire permet de
         * faire travailler le compilateur et non le processeur ?
         *
         * Note : je ne suis toujours pas sur que this -> soit obligatoire :-S
         */
        this->value = (this->value >=0 ? this->value : 360 - this->value); 
    }
    Cela ne changera sans doute pas grand chose, mais la logique est plus simple, tu ne trouve pas ?
    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

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


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

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

    Informations forums :
    Inscription : Mai 2008
    Messages : 26 855
    Points : 218 548
    Points
    218 548
    Billets dans le blog
    118
    Par défaut
    La dernière fois que j'ai essayé le module, il ne fonctionnait pas avec les floats. Ou alors, il y a un truc que je loupe complètement.
    Pour l'opérateur de conversion, si, je voulais utiliser le template, simplement que je n'ai pas compris exactement la syntaxe : .
    D'après votre remarque c'est la même que : ? Du coup, je vais templatiser la chose, c'est ce que je voulais faire.
    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.

  20. #20
    Membre émérite
    Avatar de white_tentacle
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    1 505
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 1 505
    Points : 2 799
    Points
    2 799
    Par défaut
    Je confirme que le modulo avec des flottants n’a pas de sens.

    Ce qui me dérange le plus (à part le float operator() qui devrait être un T operator() ) dans la classe que tu décris, c’est que le contrat « la valeur est comprise entre 0 et 360 » n’est pas forcément respecté : il faut un appel explicite à wrap pour le faire. Du coup, c’est au client de s’assurer que la valeur est normalisée, d’où une possible lourdeur côté utilisateur.

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 2 12 DernièreDernière

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