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

Langage C++ Discussion :

MetaProg, TypeTrait et Integral Constant


Sujet :

Langage C++

  1. #1
    Membre actif Avatar de SKone
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2004
    Messages
    333
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Canada

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mai 2004
    Messages : 333
    Points : 250
    Points
    250
    Par défaut MetaProg, TypeTrait et Integral Constant
    Bonjour,

    Je cherche à calculer des puissances de 2 à la compilation de la manière suivante :
    Code C++ : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    template < uint64_t uPower >
    struct Power2
    {
    	static uint64_t const Value =  2*Power2< uPower - 1 >::Value;
    };
     
    template <>
    struct Power2< 0 >
    {
    	static uint64_t const Value = 1;
    };

    Le problème de cette méthode c'est que cela fonctionne si et seulement si uPower est une uint64_t.

    Donc j'implémente ça :
    Code C++ : 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
    template < typename T, T uPower >
    struct Power2
    {
    	static T const Value =  static_cast< T >( 2 )*Power2< uPower - static_cast< T >( 1 ) >::Value;
    };
     
    // Par contre je dois spécialisé pour tout mes types.
    template <>
    struct Power2< uint64_t, 0 >
    {
    	static uint64_t const Value = 1;
    };
     
    template <>
    struct Power2< uint32_t, 0 >
    {
    	static uint32_t const Value = 1;
    };
     
    // ...

    Aucun problème par contre dans mon code j'ai u128 et u256 (qui sont des classes pour représenter des unsigned int 128 et 256 bits).

    Et je ne peux pas spécialisé puisqu'on ne peut pas avoir de constante "non-integral".

    J'avais essayé le truc :
    Code C++ : 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
    template < typename T >
    struct Power2
    {
    	static T::value_type const Value = static_cast< T::value_type >( 2 )*Power2< std::integral_constant< T::value_type, T::value - static_cast< T::value_type >( 1 ) > >::Value;
    };
     
    template <>
    struct Power2< std::integral_constant< uint32_t, 0 > >
    {
    	static uint32_t const Value = 1;
    };
     
    template <>
    struct Power2< std::integral_constant< uint64_t, 0 > >
    {
    	static uint64_t const Value = 1;
    };
     
    // ...

    Mais la spécialisation comme prévu pour mes types ne fonctionnes pas pour les mêmes raisons. Const non integral impossible.
    Code C++ : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    static u128 const u128Zero( 0 );
    static u256 const u256Zero( 0 );
     
    template <>
    struct Power2< std::integral_constant< u128, u128Zero > >
    {
    	static u128 const Value = u128Zero;
    };
     
    template <>
    struct Power2< std::integral_constant< u256, u256Zero > >
    {
    	static u256 const Value = u256Zero;
    };

    Connaissez-vous une solution pour résoudre ce problème ?

    Merci

  2. #2
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 189
    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 189
    Points : 17 141
    Points
    17 141
    Par défaut
    j'imagine qu'il te faudrait un constructeur public implicite prenant un intégral en argument.
    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

  3. #3
    Invité
    Invité(e)
    Par défaut
    hello,

    d'apres stack

    tu peux definir ton const en dehors de ta classe
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    template <>
    struct Power2< std::integral_constant< u256, u256Zero > >
    {
    	static u256 const Value;
    };
    template<>
    const u256  Power2<std::integral_constant< u256, u256Zero >>::_value = u256Zero;

  4. #4
    Membre actif Avatar de SKone
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2004
    Messages
    333
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Canada

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mai 2004
    Messages : 333
    Points : 250
    Points
    250
    Par défaut
    leternel> Cela ne change rien puisque le C++ interdit les constants non "integral"
    galerien69> On pourrait mais le problème n'est pas la définition d'une constante non integral mais la spécialisation d'un template avec un non integral :
    Code C++ : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    template <>
    struct Power2< std::integral_constant< u256, u256Zero > >
    {
    	static u256 const Value;
    };
    template<>
    const u256  Power2<std::integral_constant< u256, u256Zero >>::_value = u256Zero;

    Ne fonctionne pas puisque std::integral_constant ne peut pas être spécialisé avec des "non integral". C'est dans le nom "integral_constant"

    La spécialisation avec un non integral est impossible mais comment peut-on contourner ce problème ?

    Merci

  5. #5
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 189
    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 189
    Points : 17 141
    Points
    17 141
    Par défaut
    il pourrait suffire de spécialiser std::integral_constant pour ton type pseudo-intégral, en vérifiant que cela respecte bien la sémantique définie.
    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

  6. #6
    Membre actif Avatar de SKone
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2004
    Messages
    333
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Canada

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mai 2004
    Messages : 333
    Points : 250
    Points
    250
    Par défaut
    leternel > Tu aurais un exemple fonctionnelle ?

    Merci

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

    A priori je ne vois pas de solution en partant de ce que tu as déjà fait.

    Tu as vraiment besoin de pouvoir faire les manipulations à la compilation et à l’exécution ? Si ce n'est pas le cas, tu pourrais essayer de faire manipuler des pairs de std::integral à ton meta-programme pour représenter un entier (a*m+b comme tu as du faire pour créer ton type avec une pair de uint_64).

  8. #8
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 189
    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 189
    Points : 17 141
    Points
    17 141
    Par défaut
    Citation Envoyé par SKone Voir le message
    leternel > Tu aurais un exemple fonctionnelle ?

    Merci
    Non, parce que je n'en ai pas sous la main.
    Mais les politiques et traits sont souvent "extensibles" en les spécialisant pour un type précis.

    J'ai bien dis "spécialiser" pas "instancier"
    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

  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
    leternel> Le problème ce n'est pas tant le type, mais la valeur qui va avec <class T, T t>. Si le type n'est pas un type entier, tu ne peux pas l'utiliser comme second paramètre template (et faire tout les calculs qui vont avec). Et l'ensemble des types entiers est fixé, si ton type n'en fait pas parti, il n'en fait pas parti.

  10. #10
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 189
    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 189
    Points : 17 141
    Points
    17 141
    Par défaut
    J'en prends note, merci.
    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

  11. #11
    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 Flob90 Voir le message
    Bonjour,

    A priori je ne vois pas de solution en partant de ce que tu as déjà fait.

    Tu as vraiment besoin de pouvoir faire les manipulations à la compilation et à l’exécution ? Si ce n'est pas le cas, tu pourrais essayer de faire manipuler des pairs de std::integral à ton meta-programme pour représenter un entier (a*m+b comme tu as du faire pour créer ton type avec une pair de uint_64).
    Ca semble une bonne idée, ça réduit les puissance de 2 sur les u128 à 1 multiplication et à 3 multiplications sur les u256. (pas de constexpr par contre )

    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
    #include <iostream>
     
    template <uint32_t uPower, int var=0>
    struct Power2 { };
     
    template <uint32_t uPower>
    struct Power2<uPower, 0> {
    	static const uint64_t t256_a = 2*Power2<uPower-1, 1>::t256_a;
    	static const uint64_t t256_b = Power2<uPower-1, 1>::t256_b;
    	static const uint64_t t256_c = Power2<uPower-1, 1>::t256_c;
    	static const uint64_t t256_d = Power2<uPower-1, 1>::t256_d;
     
    	static const uint64_t t128_a = 2*Power2<uPower-1, 1>::t128_a;
    	static const uint64_t t128_b = Power2<uPower-1, 1>::t128_b;
     
    	static const uint32_t t32 = (uint32_t)(t256_a*t256_b*t256_c*t256_d);
    	static const uint64_t t64 = t256_a*t256_b*t256_c*t256_d;
    };
     
    template <uint32_t uPower>
    struct Power2<uPower, 1> {
    	static const uint64_t t256_a = Power2<uPower-1, 2>::t256_a;
    	static const uint64_t t256_b = 2*Power2<uPower-1, 2>::t256_b;
    	static const uint64_t t256_c = Power2<uPower-1, 2>::t256_c;
    	static const uint64_t t256_d = Power2<uPower-1, 2>::t256_d;
     
    	static const uint64_t t128_a = Power2<uPower-1, 2>::t128_a;
    	static const uint64_t t128_b = 2*Power2<uPower-1, 2>::t128_b;
     
    	static const uint32_t t32 = (uint32_t)(t256_a*t256_b*t256_c*t256_d);
    	static const uint64_t t64 = t256_a*t256_b*t256_c*t256_d;
    };
     
    template <uint32_t uPower>
    struct Power2<uPower, 2> {
    	static const uint64_t t256_a = Power2<uPower-1, 3>::t256_a;
    	static const uint64_t t256_b = Power2<uPower-1, 3>::t256_b;
    	static const uint64_t t256_c = 2*Power2<uPower-1, 3>::t256_c;
    	static const uint64_t t256_d = Power2<uPower-1, 3>::t256_d;
     
    	static const uint64_t t128_a = 2*Power2<uPower-1, 3>::t128_a;
    	static const uint64_t t128_b = Power2<uPower-1, 3>::t128_b;
     
    	static const uint32_t t32 = (uint32_t)(t256_a*t256_b*t256_c*t256_d);
    	static const uint64_t t64 = t256_a*t256_b*t256_c*t256_d;
    };
     
    template <uint32_t uPower>
    struct Power2<uPower, 3> {
    	static const uint64_t t256_a = Power2<uPower-1, 0>::t256_a;
    	static const uint64_t t256_b = Power2<uPower-1, 0>::t256_b;
    	static const uint64_t t256_c = Power2<uPower-1, 0>::t256_c;
    	static const uint64_t t256_d = 2*Power2<uPower-1, 0>::t256_d;
     
    	static const uint64_t t128_a = Power2<uPower-1, 0>::t128_a;
    	static const uint64_t t128_b = 2*Power2<uPower-1, 0>::t128_b;
     
    	static const uint32_t t32 = (uint32_t)(t256_a*t256_b*t256_c*t256_d);
    	static const uint64_t t64 = t256_a*t256_b*t256_c*t256_d;
    };
     
    template <>
    struct Power2< 0, 0 >
    {
    	static const uint64_t t256_a = 1;
    	static const uint64_t t256_b = 1;
    	static const uint64_t t256_c = 1;
    	static const uint64_t t256_d = 1;
     
    	static const uint64_t t128_a = 1;
    	static const uint64_t t128_b = 1;
     
    	static const uint32_t t32 = (uint32_t)(t256_a*t256_b*t256_c*t256_d);
    	static const uint64_t t64 = t256_a*t256_b*t256_c*t256_d;
    };
     
    template <>
    struct Power2< 0, 1 >
    {
    	static const uint64_t t256_a = 1;
    	static const uint64_t t256_b = 1;
    	static const uint64_t t256_c = 1;
    	static const uint64_t t256_d = 1;
     
    	static const uint64_t t128_a = 1;
    	static const uint64_t t128_b = 1;
     
    	static const uint32_t t32 = (uint32_t)(t256_a*t256_b*t256_c*t256_d);
    	static const uint64_t t64 = t256_a*t256_b*t256_c*t256_d;
    };
     
    template <>
    struct Power2< 0, 2 >
    {
    	static const uint64_t t256_a = 1;
    	static const uint64_t t256_b = 1;
    	static const uint64_t t256_c = 1;
    	static const uint64_t t256_d = 1;
     
    	static const uint64_t t128_a = 1;
    	static const uint64_t t128_b = 1;
     
    	static const uint32_t t32 = (uint32_t)(t256_a*t256_b*t256_c*t256_d);
    	static const uint64_t t64 = t256_a*t256_b*t256_c*t256_d;
    };
     
    template <>
    struct Power2< 0, 3 >
    {
    	static const uint64_t t256_a = 1;
    	static const uint64_t t256_b = 1;
    	static const uint64_t t256_c = 1;
    	static const uint64_t t256_d = 1;
     
    	static const uint64_t t128_a = 1;
    	static const uint64_t t128_b = 1;
     
    	static const uint32_t t32 = (uint32_t)(t256_a*t256_b*t256_c*t256_d);
    	static const uint64_t t64 = t256_a*t256_b*t256_c*t256_d;
    };
     
    int main(int argc, char **argv) {	
    	uint64_t p256_a = Power2<200>::t256_a;
    	uint64_t p256_b = Power2<200>::t256_b;
    	uint64_t p256_c = Power2<200>::t256_c;
    	uint64_t p256_d = Power2<200>::t256_d;
     
    	uint64_t p128_a = Power2<100>::t128_a;
    	uint64_t p128_b = Power2<100>::t128_b;
     
    	uint64_t p50 = Power2<50>::t64;
     
    	uint32_t p30 = Power2<30>::t32;
     
    	std::cout << "2^200 = " << p256_a << "*" << p256_b << "*" << p256_c << "*" << p256_d << "\n";
    	std::cout << "2^100 = " << p128_a << "*" << p128_b << "\n";
    	std::cout << "2^50 = " << p50 << "\n";
    	std::cout << "2^30 = " << p30 << "\n";
     
    	return 0;
    }
    Cela permet de calculer la puissance de 2 d'un uint32 seulement, mais bon de toute façon à partir de 2^255 ça va overflow.

  12. #12
    Membre expert

    Avatar de germinolegrand
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Octobre 2010
    Messages
    738
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : Développeur de jeux vidéo
    Secteur : Tourisme - Loisirs

    Informations forums :
    Inscription : Octobre 2010
    Messages : 738
    Points : 3 892
    Points
    3 892
    Par défaut
    Pour ceux que ça intéresse, le pow contexpr C++11 :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    template <class T, class S>
    inline constexpr T pow(T n, S p)
    {
        return p ? n*pow(n, p - 1) : 1;
    }
     
    pow(567uLL, 30);
    Ce code détecte les overflows à la compilation.

Discussions similaires

  1. integrer constante php
    Par nocoment dans le forum Général JavaScript
    Réponses: 1
    Dernier message: 04/05/2007, 13h57
  2. calcul integral en c
    Par Anonymous dans le forum C
    Réponses: 3
    Dernier message: 11/01/2003, 11h32
  3. [ADO] Constantes des types de champ
    Par SpaceFrog dans le forum VB 6 et antérieur
    Réponses: 3
    Dernier message: 05/09/2002, 11h08
  4. Réponses: 10
    Dernier message: 27/08/2002, 23h24
  5. Au sujet des constantes
    Par FranT dans le forum Langage
    Réponses: 8
    Dernier message: 09/08/2002, 11h03

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