Bonjour à tous,
Je fais suite à cette conversation dans la rubrique « Langage » étant donné que ça n'a plus rien à voir avec Boost.
Pour résumer :
Il existe la bibliothèque boost::concept_check qui permet de formaliser des concepts à partir d'un ensemble d'expressions. C'est pratique (pour avoir des messages d'erreurs plus explicites) et très expressif, mais ça ne permet pas de faire de surcharge. Il y a donc une grosse perte d'intérêt par rapport aux concepts initiaux de C++0x qui, je le rappelle, ont été abandonnés.
Il y a cependant un espoir : il sera possible (et même est possible avec GCC 4.4 et peut-être d'autres compilateurs récents) d'exploiter le mécanisme SFINAE pour les expressions. Il faut bien sûr que l'expression apparaisse dans la signature de la fonction à surcharger ; pour ce faire on utilise decltype, également nouvelle fonctionnalité de C++0x.
Rien de plus clair qu'un petit exemple.
On a une classe X et un classe Y.
Il est possible de multiplier des X entre eux, mais pas des Y.
Il est possible d'additionner des Y entre eux, mais pas des X.
On souhaite surcharger le template de fonction f :
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 #include <iostream> struct X { X(int value): value_(value) { } int value_; }; X operator*(X x1, X x2) { return X(x1.value_ * x2.value_); } struct Y { Y(int value): value_(value) { } int value_; }; Y operator+(Y y1, Y y2) { return Y(y1.value_ + y2.value_); } template<class T> auto f(T t1, T t2) -> decltype(t1 + t2) // #1 { std::cout << "#1\n"; return t1 + t2; } template<class T> auto f(T t1, T t2) -> decltype(t1 * t2) // #2 { std::cout << "#2\n"; return t1 * t2; } int main() { X x1(0), x2(0); X x3 = f(x1, x2); // deduction fails on #1 (cannot add X+X), calls #2 Y y1(0), y2(0); Y y3 = f(y1, y2); // calls #1 }
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 #2 #1
Il est tout à fait possible d'utiliser le mécanisme avec des signatures de fonction classiques (c'est-à-dire n'ayant pas la forme « auto f() -> decltype »), en utilisant par exemple un « paramètre fantôme » (comme on peut le faire avec boost::enable_if) :
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 template<typename> class require { public: typedef void* type; }; //#1 template<class T> T f(T t1, T t2, typename require<decltype(t1 * t2)>::type = 0) { std::cout << "#1\n"; return t1 * t2; } //#2 template<class T> T f(T t1, T t2, typename require<decltype(t1 + t2)>::type = 0) { std::cout << "#2\n"; return t1 + t2; } int main() { X x1(0), x2(0); Y y1(0), y2(0); X x3 = f(x1, x2); //calls #1 Y y3 = f(y1, y2); //calls #2 }
Pensez-vous qu'à partir de cette piste, il soit possible d'externaliser les expressions et de les regrouper dans une même classe qui serait alors une classe « concept » (de la même façon qu'avec boost::concept_check, pour ceux qui connaissent) ?
Au fond de moi je me dis « si c'était possible, ça se saurait, un gourou en aurait déjà parlé au moment du tollé lors de l'abandon des concepts », mais je tente tout de même le coup.








Répondre avec citation




Partager