La présentation est en train de télécharger. S'il vous plaît, attendez

La présentation est en train de télécharger. S'il vous plaît, attendez

DÉCORER AVEC DES UNITÉS Séminaire technique Cours C++(++) 1.

Présentations similaires


Présentation au sujet: "DÉCORER AVEC DES UNITÉS Séminaire technique Cours C++(++) 1."— Transcription de la présentation:

1 DÉCORER AVEC DES UNITÉS Séminaire technique Cours C++(++) 1

2 Qu’allons nous voir? Première partie Pourquoi? Les autres librairies Units! Seconde partie Quelques notions de métaprogrammation Concept d’unités ScaledUnit PoweredUnit ComposedUnit Vector 2

3 Pourquoi ajouter des unités? // Calcule la distance, en mètre double CalculerDistance(double depart, double fin) { return fin – depart; } void main() { double start = 10.0; // En m double end = 50.0; // En km double dist = CalculerDistance(start, end); … } 3

4 Pourquoi ajouter des unités? // Calcule la distance, en mètre double CalculerDistance(double vitesse, double t) { return vitesse * t; } void main() { double start = 10.0; // En mètre double end = 50.0; // En mètre double dist = CalculerDistance(start, end); … } 4

5 // Calcule la distance, en mètre Metre CalculerDistance(Speed vitesse, Second t) { return vitesse * t; } … void main() { Metre start = 10.0; // En mètre Metre end = 50.0; // En mètre Metre dist = CalculerDistance(start, end); … } Pourquoi ajouter des unités? Erreur de compilation (Le plus clair possible) 5

6 // Calcule la distance, en mètre Metre CalculerDistance(Metre debut, Metre fin) { return fin - debut; } … void main() { Kilometre start = 10.0; // En kilomètre Kilometre end = 50.0; // En kilomètre Metre dist = CalculerDistance(start, end); … } Pourquoi ajouter des unités? Transformation automatique 6

7 Les autres librairies Boost::Unit www.boost.org OpenFrameworks Unités de Callum Grant www.openframework.cc 7

8 Boost::Units #include … quantity cm(4 * centi * meter); quantity m(4 * meter); quantity r1 = cm + m; cm contient 0.04 r1 contient 4.04 8

9 Boost::Units quantity cm(4 * centi * meter); quantity m(4 * meter); quantity a(4 * ampere); quantity c(2 * coulomb); quantity n(2 * newton); auto r2 = cm * m * a / (c * n); r2 contient 0.16 m.kg^-1.s quantity ::type, si::system> > r2 9

10 Boost::Units quantity cm(4 * centi * meter); quantity s(4 * second); auto r3 = cm + s; 22 erreurs de compilation 20 dans xstring et xutility. 10

11 Boost::Units Une dans boost : La spécialisation du modèle de fonction ‘add_typeof_helper, quantity >::type operator+(const quantity &, quantity &)’ a échoué. L’autre : ‘+’ binaire : ‘quantity ’ ne défini pas cet opérateur ou une conversion vers un type acceptable pour l’opérateur prédéfini. 11 1 er prix pour la clarté!

12 OpenFramework (Callum Grant) #include meters_by_second speed = cm(4) / s(4); auto result = cm(4) + s(4); // Erreur de compilation! ‘Util::Units::Internals::Convert ::checkConvertible’ utilise une struct de ‘Util::Units::Internals::static_assert2 ’ non défini. Hein??? 12

13 OpenFramework (Callum Grant) auto result = cm(4) * m(4) * A(4) / (C(2) * N(2)); cout<<result<<endl; 16 cm.m.A.(C.N)^-1 !?!?!?! 0.16 m.s.kg^-1 16 cm.s.kg^-1 13

14 Units! #include Metre m1 = Metre(4); Centimetre cm1 = Centimetre(4); Centimetre r1 = cm1 + m1; Speed r2 = cm1 / Second(2); auto r3 = cm1 + Second(4); // Erreur de compilation ‘+’ binaire : aucun opérateur trouvé qui accepte un opérande de partie droite de type ‘Second’ (ou il n’existe pas de conversion acceptable) 14

15 Units! Centimetre cm(4); Metre m(4); Ampere a(4); auto r2 = m * cm * a / (Coulomb(2) * Newton(2)); r2 contient 0.16 m.kg^-1.s Divide ::Type, Kilogram>::Type r2; ComposedUnit, PoweredUnit > r2; 15

16 Déclaration d’unité ScaledUnit Centimètre, Milliseconde, etc. struct metreBase; typedef standard ::Type Metre; typedef centi ::Type Centimetre; template struct standard { typedef ScaledUnit Type; }; template struct centi { typedef ScaledUnit Type; }; 16

17 Déclaration d’unité ScaledUnit Centimètre, Milliseconde, etc. struct secondBase; typedef standard ::Type Second; typedef ScaledUnit Minute; typedef ScaledUnit Hour; typedef ScaledUnit Day; 17

18 Déclaration d’unité PoweredUnit Centimètre carré, Seconde carré, etc. typedef PoweredUnit Centimetre2; typedef PoweredUnit SecondM2; 18

19 Déclaration d’unité ComposedUnit Newton (Kilogramme mètre par seconde carré), Coulomb, etc. typedef ComposedUnit, SecondM2> Newton; typedef Divide ::Type, Second2>::Type Newton; 19

20 Déclaration d’une nouvelle unité typedef ScaledUnit PiedDeRoi; typedef ScaledUnit Toise; typedef ScaledUnit PercheDuRoi; 20

21 Utilisation de la valeur d’une unité Pour faire le lien avec d’autres librairies Pour court-circuiter la validation du compilateur double val = Metre(4).Value(); 21

22 Où trouver la librairie? http://www.info.usherbrooke.ca/vducharme/Units/Units.h 22

23 NOTIONS DE MÉTAPROGRAMMATION 23

24 Rappel - Templates template class Foo { bool foo(T val1, T val2) { return val1 == val2; } } void main() { Foo iFoo; Foo dFoo; cout<<iFoo.foo(1,2)<<dFoo.foo(0.0,0.0)<<endl; } 24

25 Rappel - Templates template class Foo { bool foo(T val1, T val2) { return val1 == val2; } } template<> class Foo { bool foo(double val1, double val2) { return val1 != val2; } 25

26 Vérifier si deux types sont identiques template struct SameTypes { enum{ Result = 0 }; }; template struct SameTypes { enum{ Result = 1 }; }; 26 SameTypes ::Result

27 If Else Statique qui retourne des entiers template struct IfElseInt; template struct IfElseInt { enum { Result = T }; }; template struct IfElseInt { enum { Result = F }; }; 27

28 If Else Statique qui retourne des types template struct IfElseType; template struct IfElseType { typedef T Result; }; template struct IfElseType { typedef F Result; }; 28

29 CONCEPTS D’UNITÉS 29

30 Les constructeurs explicit Metre m = 5; Metre m2 = Metre(5); explicit Unit(const double val = 0.0) : m_value(val) { } 30 Erreur de compilation

31 Opération communes sur des unités Opérations logiques Addition/Soustraction Multiplication par une valeur sans unité Division (par la même unité ou une valeur sans unité) 31

32 Curiously Recurring Template Pattern Le nom de l’enfant est contenu dans le paramètre générique (template) du parent template class B { … }; class D : public B { … }; 32

33 Curiously Recurring Template Pattern template class Unit { … }; template<typename U, int N = 1, int D = 1, typename UBase = typename GetBaseUnit ::BaseUnit> class ScaledUnit : public Unit > { }; 33

34 Curiously Recurring Template Pattern Copy Constructeur Unit(const U& u) : m_value(u.m_value) { } 34

35 Curiously Recurring Template Pattern Opérations logiques bool operator==(const U& u) const { return m_value == u.m_value; } bool operator!=(const U& u) const { return !(*this == u); } … 35

36 Curiously Recurring Template Pattern Addition et soustraction U operator-(const U& u) const { return U(m_value - u.m_value); } U operator+(const U& u) const { return U(m_value + u.m_value); } 36

37 Curiously Recurring Template Pattern Multiplication et division U operator*(double u) const { return U(m_value * u); } Scalar operator/(const U& u) const { return Scalar(m_value / u.m_value); } 37

38 Trois types pour les unités ScaledUnit Centimètre, Milliseconde, etc. PoweredUnit Centimètre carré, Seconde carré, etc. ComposedUnit Newton (Kilogramme mètre par seconde carré), Coulomb, etc. Scalar! Sans unité 38

39 La classe ScaledUnit template<typename U, int N = 1, int D = 1, typename UBase = typename GetBaseUnit ::BaseUnit> class ScaledUnit : public Unit > { … }; 39

40 La classe PoweredUnit template<typename U, int N, int D = 1, typename UBase = typename GetBaseUnit ::BaseUnit> class PoweredUnit : public Unit > { … } 40

41 template struct GetBaseUnit { typedef U BaseUnit; }; template struct GetBaseUnit > { typedef SUBase BaseUnit; }; template struct GetBaseUnit > { typedef PUBase BaseUnit; }; 41 Utilitaire GetBaseUnit

42 La classe ComposedUnit template class ComposedUnit : public Unit > { … } 42

43 Conversion Centimetre cm(Decimetre(4)); 4 dm  40 cm Centimetre : ScaledUnit Decimetre : ScaledUnit (D To * N From ) / (N To * D From ) = Facteur (100 * 1) / (1 * 10) = 10 43 From To

44 template struct GetScaleChange { static double Get() { return (static_cast (DT)* static_cast (NF)) / (static_cast (NT)* static_cast (DF)); } }; template struct GetScaleChange { static double Get() { return 1.0; } }; 44 Utilitaire GetScaleChange

45 Conversion Centimetre2 cm(Decimetre2(4)); 4 dm 2  400 cm 2 Centimetre2 : PoweredUnit Decimetre2 : PoweredUnit ((D To * N From ) / (N To * D From ))^(N Power /D Power ) = Facteur ((100 * 1) / (1 * 10))^(2/1) = 100 45

46 template struct GetChangeFactorBase { static double GetFactor() { return pow(GetScaleChange ::Get(), (N / static_cast (D))); } }; template struct GetChangeFactorBase { static double GetFactor() { return GetScaleChange ::Get(); } }; 46 Utilitaire GetChangeFactorBase

47 template struct ChangeFactor { … static double GetValue(double value) { return value * GetChangeFactorBase ::Num, GetScale ::Den, GetScale ::Num, GetScale ::Den, GetPower ::Num, GetPower ::Den>::GetFactor(); } }; 47 Utilitaire ChangeFactor

48 template struct GetScale { static const uint64 Num = 1; static const uint64 Den = 1; }; template struct GetScale > { static const uint64 Num = N * GetScale ::Num; static const uint64 Den = D * GetScale ::Den; }; template struct GetScale > { static const uint64 Num = GetScale ::Num; static const uint64 Den = GetScale ::Den; }; 48 Utilitaire GetScale

49 template struct GetPower { enum { Num = 1, Den = 1 }; template struct GetPower > { enum { Num = GetPower ::Num * N, Den = GetPower ::Den * D }; 49 Utilitaire GetPower

50 ScaledUnit 50

51 Constructeur template ScaledUnit(const ScaledUnit & u) : Unit >( ChangeFactor, ScaledUnit >::GetValue(u.Value()) ) { … } 51

52 Multiplication et division générale Unité * Unité = Unité 2 Unité / Unité = Sans Unité Unité * Unité N/D = Unité (N/D)+1 Unité * Unité -1 = Sans Unité Unité / Unité N/D = Unité (N/D)-1 Unité * Unité2 = Composition(Unité, Unité2) 52

53 Les traits template struct OperatorResultType { typedef ScaledUnit MultiplyType; typedef ScaledUnit DivideType; }; 53

54 Les traits template struct OperatorResultType > { typedef PoweredUnit, 2, 1, UBase> MultiplyType; typedef Scalar DivideType; }; 54

55 If Else Statique template struct IfElseType; template struct IfElseType { typedef T Result; }; template struct IfElseType { typedef F Result; }; 55

56 template struct OperatorResultType > { typedef typename IfElseType<PN + PD == 0, Scalar, PoweredUnit, PN + PD, PD, UBase> >::Result MultiplyType; typedef typename IfElseType<PD - PN == 0, Scalar, PoweredUnit, PD - PN, PD, UBase> >::Result DivideType; }; 56 Trait OperatorResultType avec PoweredUnit

57 Multiplication typename OperatorResultType >::MultiplyType operator*(const ScaledUnit & u) const { return typename OperatorResultType >::MultiplyType(Value() * u.Value()); } 57

58 Multiplication template typename OperatorResultType >::MultiplyType operator*(const ScaledUnit & u) const { typedef ChangeFactor, ScaledUnit > ChangeFactorType; return typename OperatorResultType >::MultiplyType(Value() * ChangeFactorType::GetValue(u.Value())); } 58

59 Multiplication template typename TransformUnit, ScaledUnit >::MultiplyType operator*(const ScaledUnit & u) const { typedef TransformUnit, ScaledUnit > TransformType; return TransformType::Multiply(*this, u); } 59

60 PoweredUnit Comme les ScaledUnit, avec des traits différents 60

61 Les traits template struct OperatorResultType > { typedef typename IfElseType<N + D == 0, Scalar, PoweredUnit >::Result MultiplyType; }; 61

62 template struct OperatorResultType >{ typedef typename IfElseType<(N*PD + D*PN) % (D*PD) == 0, typename IfElseType<(N*PD) + (D*PN) == 0, Scalar, typename IfElseType<(N*PD) + (PN*D) == (D*PD), U, PoweredUnit<U, ((N*PD) + (D*PN)) / (D*PD), 1, UBase> >::Result >::Result, PoweredUnit<U, ((N*PD) + (PN*D)) / PGCD ::Value, (D*PD) / PGCD ::Value, UBase> >::Result MultiplyType; }; 62 Trait OperatorResultType avec PoweredUnit

63 Calcul du PGCD template struct PGCD { enum { Value = PGCD ::Value }; }; template struct PGCD { enum { Value = M }; }; 63

64 ComposedUnit 64

65 Particularités On compose par la gauche ComposedUnit, C>, D> Pas besoin de traits comme les autres unités On va utiliser la structure « TransformUnit » Permet de combiner et simplifier des unités Metre.Kilogram.Second -2 == Kilogram.Metre.Second -2 Metre.Kilogram.Second -2 == Kilogram.Centimetre.Second -2 65

66 Utilisation de TransformUnit template typename TransformUnit, ScaledUnit >::MultiplyType operator*(const ScaledUnit & u) const { typedef TransformUnit, ScaledUnit > TransformType; return TransformType::Multiply(*this, u); } 66

67 template struct TransformUnit { typedef typename TransformBase ::ReturnTypeMultiply MultiplyType; typedef typename TransformBase ::ReturnTypeDivide DivideType; static MultiplyType Multiply(const U& u, const V& v) { return MultiplyType(u.Value() * (v.Value() * TransformBase ::GetChangeFactorMultiply())); } static DivideType Divide(const U& u, const V& v) { return DivideType(u.Value() / (v.Value() * TransformBase ::GetChangeFactorDivide())); } }; 67 Utilitaire TransformUnit

68 template struct TransformBase { typedef typename Transform ::ReturnTypeMultiply MultiplyResultType; typedef typename Transform ::ReturnTypeDivide DivideResultType; enum { FindMultiply = Transform ::Find, FindDivide = Transform ::Find }; typedef typename IfElseType<FindMultiply, MultiplyResultType, ComposedUnit >::Result ReturnTypeMultiply; typedef typename IfElseType<FindDivide, DivideResultType, ComposedUnit ::TypeReturn> >::Result ReturnTypeDivide; 68 Utilitaire TransformBase

69 … static double GetChangeFactorMultiply() { return Transform ::GetChangeFactor(); } static double GetChangeFactorDivide() { return Transform ::GetChangeFactor(); } }; 69 Utilitaire TransformBase

70 template struct TransformBase > { typedef typename TransformBase ::ReturnTypeMultiply IntermediateMultiplyType; typedef TransformBase MultiplyType; typedef typename MultiplyType::ReturnTypeMultiply ReturnTypeMultiply; enum { FindMultiply = MultiplyType::FindMultiply, … }; static double GetChangeFactorMultiply() { double f = TransformBase ::GetChangeFactorMultiply(); return MultiplyType::GetChangeFactorMultiply() * f; } }; 70 Utilitaire TransformBase avec ComposedUnit

71 template struct Transform; template struct Transform { typedef V ReturnTypeMultiply; typedef typename InversePower ::TypeReturn ReturnTypeDivide; enum { Find = 1 }; static double GetChangeFactor() { return 1.0; } }; 71 Utilitaire Transform

72 template struct Transform, V> { typedef typename ScaledUnit ::template OperatorResultType ::MultiplyType MultiplyResultType; enum { Find = SameTypes ::Result || SameTypes ::BaseUnit, UBase>::Result, VIsScalar = SameTypes ::Result }; typedef MultiplyResultType ReturnTypeMultiply; static double GetChangeFactor() { if (Find && !VIsScalar) return ChangeFactor, V>::GetFactor(); return 1.0; } }; 72 Utilitaire Transform

73 template struct Transform, V> { typedef typename Transform ::MultiplyResultType U1MultiplyType; typedef typename Transform ::MultiplyResultType U2MultiplyType; typedef typename ComposedUnit MultiplyResultTypeNoScalarFound; enum { Find = Transform ::Find || Transform ::Find || SameTypes, V>::Result }; static double GetChangeFactor() { double changeFactorU1 = Transform ::GetChangeFactor(); double changeFactorU2 = Transform ::GetChangeFactor(); return changeFactorU1 * changeFactorU2; } 73 Utilitaire Transform

74 // If we find a match // If (U1*V==Scalar) ResultType = U2 // elseif (U2*V==Scalar) ResultType = U1 // else ResultType = ComposedUnit // Otherwise, ResultType = ComposedUnit typedef typename IfElseType<SameTypes<Scalar, U1MultiplyType >::Result, U2, MultiplyResultTypeNoScalarFound>::Result FoundMultiplyTypeStep1; typedef typename IfElseType<SameTypes<Scalar, U2MultiplyType>::Result, U1, FoundMultiplyTypeStep1>::Result FoundMultiplyTypeStep2; typedef typename IfElseType<Find, FoundMultiplyTypeStep2, ComposedUnit >::Result ReturnTypeMultiply; typedef ReturnTypeMultiply MultiplyResultType; }; 74 Utilitaire Transform

75 Particularités Pas besoin de traits comme les autres unités On va utiliser la structure « TransformUnit » Metre.Kilogram.Second -2 == Kilogram.Metre.Second -2 Metre.Kilogram.Second -2 == Kilogram.Centimetre.Second -2 75

76 ComposedExactlyEqual template struct ComposedExactlyEqual; template struct ComposedExactlyEqual, ComposedUnit > { enum { Equal = ComposedEqual, ComposedUnit >::Find && ComposedEqual, ComposedUnit >::Find }; typedef typename IfElseType<Equal, ComposedUnit, ComposedUnit >::Result Type; }; 76

77 SFINAE Substitution Failure Is Not An Error Une erreur lors d’une spécialisation de template ne fait pas d’erreur de programmation! Tant qu’il y a au moins une spécialisation qui fonctionne, il n’y a pas d’erreur et la spécialisation est générée. Si ça ne fonctionne pas, aucune génération n’a lieu 77

78 SFINAE struct Test { typedef int foo; }; template void f(typename T::foo) { … } // Définition #1 template void f(T) { … } // Définition #2 int main() { f (10); // Appel #1. f (10); // Appel #2. Sans erreur (même s’il n’y a // pas de int::foo) grâce à SFINAE } 78

79 Permettre une méthode selon une condition template struct EnableIf { typedef T Type; }; template struct EnableIf {}; 79 Les structures ne contiennent pas la même interface! SFINAE!

80 template typename EnableIf, ComposedUnit >::Equivalent, ComposedUnit >::Type& operator=(const ComposedUnit & v) { double f = ComposedExactlyEqual, ComposedUnit >::GetChangeFactor(); Unit >::m_value = v.Value() * f; return *this; } 80 Assignation d’un ComposedUnit

81 Fonctions utilitaires template typename SqrtTransform ::TypeReturn sqrt(const Unit & u) { return SqrtTransform ::TypeReturn(sqrt(u.Value())); } template typename InversePower ::TypeReturn operator/(const double& d, const Unit & u) { return InversePower ::TypeReturn(d / u.Value()); } 81

82 template struct SqrtTransform { typedef PoweredUnit<U, 1, 2, typename GetBaseUnit ::BaseUnit> TypeReturn; }; 82 Utilitaire SqrtTransform

83 template struct SqrtTransform > { enum { RN = IfElseInt ::Result, RD = IfElseInt ::Result }; typedef typename IfElseType<RN == RD, U, PoweredUnit >::Result TypeReturn; }; 83 Utilitaire SqrtTransform

84 template struct SqrtTransform > { typedef ComposedUnit ::TypeReturn, typename SqrtTransform ::TypeReturn > TypeReturn; }; 84 Utilitaire SqrtTransform

85 template struct InversePower { typedef PoweredUnit<U, -1, 1, typename GetBaseUnit ::BaseUnit > TypeReturn; }; template<> struct InversePower { typedef Scalar TypeReturn; }; 85 Utilitaire InversePower

86 template struct InversePower > { typedef PoweredUnit TypeReturn; }; template struct InversePower > { typedef V TypeReturn; }; 86 Utilitaire InversePower

87 template struct InversePower > { typedef ComposedUnit ::TypeReturn, typename InversePower ::TypeReturn > TypeReturn; }; 87 Utilitaire InversePower

88 Vector 88

89 Vector Vecteur mathématique en 3 dimensions Fonctionne avec les unités Vector distance; Second time; Vector vSpeed = distance / time; 89

90 CONCLUSION Finalement! 90

91 Conclusion - Unités Ajoute une couche de validation à la compilation Plus besoin de se soucier des conversions Permet une interopérabilité entre différents systèmes (métrique et impérial) 91

92 Conclusion – C++ et généricité Sky is the limit! Façon différente de penser des algorithmes Se rapproche beaucoup des langages fonctionnels 92

93 QUESTIONS? 93


Télécharger ppt "DÉCORER AVEC DES UNITÉS Séminaire technique Cours C++(++) 1."

Présentations similaires


Annonces Google