Télécharger la présentation
La présentation est en train de télécharger. S'il vous plaît, attendez
Publié parÈve St-Georges Modifié depuis plus de 9 années
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
Présentations similaires
© 2024 SlidePlayer.fr Inc.
All rights reserved.