-
Notifications
You must be signed in to change notification settings - Fork 16
/
metaprogramming.txt
85 lines (73 loc) · 6.27 KB
/
metaprogramming.txt
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
METAPROGRAMMING
METAFONCTION ==> #Fonction agissant compile-time. Ses arguments sont donc connus compile-time.
#Ex :
# - preprocesseur
# - templates et static CLASSDT
SFINAE ==> #Substitution failure is not an error.
#Lors de la recherche d'un overload avec un argument de type TYPE :
# - si un paramètre recherche TYPE::TYPE2, et que celui-ci n'existe pas, pas d'erreur
# - s'il existe, il sera préféré à seulement TYPE.
#Utilisation : metafonction recherchant l'existence d'un trait. Exemple :
# template <class U>
# struct has_type
# {
# typedef char yes[2];
# template <class T> static char Fonc(T);
# template <class T> static yes& Fonc(typename T::type*);
# static const bool value = ( sizeof( Fonc<U>( 0 ) ) == sizeof( yes ) );
# };
METASETTER ET METAGETTER#Metafunctions (compile-time, struct sans empreinte mémoire) qui renvoient un type :
==> # - METASETTER : en fonction du template T, définit un type transformé (Est en fait un getter dans
# l'esprit). Peut aussi définir une static CLASSDT. Appelé aussi type generator.
# - METAGETTER : en fonction du template T, définit une classe indiquant la propriété recherchée dans
# T (souvent classe A ou B agissant comme des true ou false) ou une static CLASSDT (souvent true ou
# false).
#Souvent les types définis sont "...::type" et static CLASSDT "...::value".
#Il ne s'agit pas de fonctions, mais de metafonctions.
BUTS POSSIBLES ==> #Dans une fonction générique :
# - appeler des fonctions overloadées différents en fonction des propriétés de T, via un METAGETTER
# - du coup, possibilité d'optimiser et spécialiser du code générique, bien qu'il soit générique.
# Comme une template specialization, mais en plus souple et puissant.
# - transformer correctement T (ajout de constness, etc.) pour l'utiliser, via un METASETTER
# - "correctement" : même TYPE pouvant poser problème peuvent être traités via spécializations du
# METASETTER
# - vérifier concept, via METAGETTER
# - possibilité de laisser le choix de remplir un concept au client, en le laissant spécialiser
# lui-même le METAGETTER
IMPLEMENTATION ==> #Dans tout ce qui suit <> ... <...> peut être une partial ou full spécialization
METAGETTER ==> #
1) template <class T> struct METAGETTER : public A {};
template <> struct METAGETTER <...> : public B {};
FONC_DETAIL( ARGS, A ) { ... }
FONC_DETAIL( ARGS, B ) { ... }
template <class T> FONC( ARGS ) -> appelle FONC_DETAIL( ARGS, METAGETTER<T> )
2) template <class T> struct METAGETTER { typedef A type; };
template <> struct METAGETTER <...> { typedef B type };
template <class T> FONC_DETAIL( ARGS ) { ... }
template <> FONC_DETAIL<B>( ARGS ) { ... }
template <class T> FONC( ARGS ) -> appelle FONC_DETAIL<typename METAGETTER<T>::type>( ARGS )
3) template <class T> struct METAGETTER { static bool value = true; };
template <> struct METAGETTER <...> { static bool value = false; };
template <bool> FONC_DETAIL( ARGS ) { ... }
template <> FONC_DETAIL<true>(ARGS) { ... }
template <class T> FONC( ARGS ) -> appelle FONC_DETAIL<typename METAGETTER<T>::value>( ARGS )
4) Comme 1), mais A définit un ...::type renvoyant vers lui-même, et un ...::value renvoyant bool ou false.
Conséquence : peut utiliser n'importe lequel des trois appels.
Exemple : boost::true_type et boost::false_type
1 et 2 : possibilité d'avoir plus de deux valeurs différentes (contrairement à true or false). 1 appelle un véritable
argument, et non un argument de template : moins propre ni efficient que 2.
3 et 4 : possibilité de faire value && value, !, ||, ==, etc. Préférer 4.
Autres cas plus complexe de METAGETTER :
1) Utiliser 3) avec un autre type que bool, notamment un int (par exemple compter la taille d'un type d'array)
2) Utilisation d'argument de template non-paramétrique.
Ex : template <class T1, T2> struct METAGETTER { static const T1 value = T2; }
3) plusieurs membres, dont le nombre peut varier.
METASETTER ==> #
1) template <class T> struct METASETTER { typedef ... type; } //Souvent ... comprend "T"
template <> struct METASETTER <...> { typedef ... type; } // Souvent spécialization pour des cas précis
2) template <bool> struct METASETTER_DETAIL { typedef ... type; }
template <> struct METASETTER_DETAIL <true> { typedef ... type; }
template <class T> struct METASETTER { typedef METASETTER_DETAIL<METAGETTER::VALUE...> type; }
Dans tous les cas, utiliser METASETTER<T>::type