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 .
Partager