Publicité
+ Répondre à la discussion
Affichage des résultats 1 à 12 sur 12
  1. #1
    Membre confirmé Avatar de SKone
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    mai 2004
    Messages
    330
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 27
    Localisation : Canada

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

    Informations forums :
    Inscription : mai 2004
    Messages : 330
    Points : 209
    Points
    209

    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++ :
    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++ :
    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++ :
    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++ :
    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 Confirmé Sénior

    Homme Profil pro Pierre
    Ingénieur développement logiciels
    Inscrit en
    juin 2007
    Messages
    2 181
    Détails du profil
    Informations personnelles :
    Nom : Homme Pierre
    Localisation : France

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

    Informations forums :
    Inscription : juin 2007
    Messages : 2 181
    Points : 5 056
    Points
    5 056

    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.
    • La plus sotte des questions est celle qu'on ne pose pas.

    Pour faire des graphes, essayez yEd.

  3. #3
    Membre chevronné
    Homme Profil pro
    F5(){F5}
    Inscrit en
    avril 2008
    Messages
    477
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : F5(){F5}
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : avril 2008
    Messages : 477
    Points : 723
    Points
    723

    Par défaut

    hello,

    d'apres stack

    tu peux definir ton const en dehors de ta classe
    Code :
    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 confirmé Avatar de SKone
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    mai 2004
    Messages
    330
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 27
    Localisation : Canada

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

    Informations forums :
    Inscription : mai 2004
    Messages : 330
    Points : 209
    Points
    209

    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++ :
    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 Confirmé Sénior

    Homme Profil pro Pierre
    Ingénieur développement logiciels
    Inscrit en
    juin 2007
    Messages
    2 181
    Détails du profil
    Informations personnelles :
    Nom : Homme Pierre
    Localisation : France

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

    Informations forums :
    Inscription : juin 2007
    Messages : 2 181
    Points : 5 056
    Points
    5 056

    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.
    • La plus sotte des questions est celle qu'on ne pose pas.

    Pour faire des graphes, essayez yEd.

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

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

    Informations forums :
    Inscription : mai 2004
    Messages : 330
    Points : 209
    Points
    209

    Par défaut

    leternel > Tu aurais un exemple fonctionnelle ?

    Merci

  7. #7
    Expert Confirmé Avatar de Flob90
    Homme Profil pro Florian Blanchet
    Etudiant en Optique
    Inscrit en
    août 2004
    Messages
    1 320
    Détails du profil
    Informations personnelles :
    Nom : Homme Florian Blanchet
    Âge : 24
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Etudiant en Optique

    Informations forums :
    Inscription : août 2004
    Messages : 1 320
    Points : 2 913
    Points
    2 913

    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).
    "We can solve any problem by introducing an extra level of indirection" Butler Lampson

    "N'importe quel problème peut être résolu en introduisant un niveau d'indirection supplémentaire" Butler Lampson (traduction libre)

  8. #8
    Expert Confirmé Sénior

    Homme Profil pro Pierre
    Ingénieur développement logiciels
    Inscrit en
    juin 2007
    Messages
    2 181
    Détails du profil
    Informations personnelles :
    Nom : Homme Pierre
    Localisation : France

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

    Informations forums :
    Inscription : juin 2007
    Messages : 2 181
    Points : 5 056
    Points
    5 056

    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.
    • La plus sotte des questions est celle qu'on ne pose pas.

    Pour faire des graphes, essayez yEd.

  9. #9
    Expert Confirmé Avatar de Flob90
    Homme Profil pro Florian Blanchet
    Etudiant en Optique
    Inscrit en
    août 2004
    Messages
    1 320
    Détails du profil
    Informations personnelles :
    Nom : Homme Florian Blanchet
    Âge : 24
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Etudiant en Optique

    Informations forums :
    Inscription : août 2004
    Messages : 1 320
    Points : 2 913
    Points
    2 913

    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.
    "We can solve any problem by introducing an extra level of indirection" Butler Lampson

    "N'importe quel problème peut être résolu en introduisant un niveau d'indirection supplémentaire" Butler Lampson (traduction libre)

  10. #10
    Expert Confirmé Sénior

    Homme Profil pro Pierre
    Ingénieur développement logiciels
    Inscrit en
    juin 2007
    Messages
    2 181
    Détails du profil
    Informations personnelles :
    Nom : Homme Pierre
    Localisation : France

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

    Informations forums :
    Inscription : juin 2007
    Messages : 2 181
    Points : 5 056
    Points
    5 056

    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.
    • La plus sotte des questions est celle qu'on ne pose pas.

    Pour faire des graphes, essayez yEd.

  11. #11
    Membre Expert
    Homme Profil pro
    Étudiant
    Inscrit en
    juin 2012
    Messages
    852
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : juin 2012
    Messages : 852
    Points : 1 740
    Points
    1 740

    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 :
    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
    Expert Confirmé Sénior

    Avatar de germinolegrand
    Homme Profil pro Germino Legrand
    Développeur de jeux vidéo
    Inscrit en
    octobre 2010
    Messages
    731
    Détails du profil
    Informations personnelles :
    Nom : Homme Germino Legrand
    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 : 731
    Points : 4 115
    Points
    4 115

    Par défaut

    Pour ceux que ça intéresse, le pow contexpr C++11 :
    Code :
    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.
    Choisis un travail que tu aimes et tu n'auras pas à travailler un seul jour de ta vie.

    N'oubliez pas de marquer votre sujet comme et de mettre des aux messages apportant un plus à votre discussion.

    Si vous souhaitez participer à la rubrique C++, ne me contactez plus !

Liens sociaux

Règles de messages

  • Vous ne pouvez pas créer de nouvelles discussions
  • Vous ne pouvez pas envoyer des réponses
  • Vous ne pouvez pas envoyer des pièces jointes
  • Vous ne pouvez pas modifier vos messages
  •