Mon blog anglais - Mes articles et critiques de livres - FAQ C++0x, avec liste des nouveautés - Conseils sur le C++ - La meilleure FAQ du monde - Avant de créer des classes que vous réutiliserez, regardez si ça n'existe pas déjà - Le site du comité de normalisation du C++
Le guide pour bien débuter en C++ - Cours et tutoriels pour apprendre C++
Ressources proposées par 3DArchi - Les fonctions virtuelles en C++ - Cours et tutoriels C++ - FAQ C++ - Forum C++.
Si seulement. En fait, c'était mon problème initial, que de pas pouvoir nommer un paramètre void.
Maintenant, mon problème a changé: je ne peux pas avoir un deuxième paramètre qui soit void. (En fait, j'ai besoin d'un autre paramètre, en dehors de celui de la classe parente qui peut être void, pour rester fidèle le plus possible au principe de RAII).
Pour revenir, mon problème initial, c'était de comment éviter d'avoir à écrire du code redondant. Je m'explique: selon la classe parente, le constructeur de classe parente peut ou ne pas prendre de paramètre.
Or il est impossible de spécialiser partiellement une fonction, qui serait ici le constructeur du template intermédiaire InstanceOf<>, pour prendre aucun ou un paramètre.
Mais je peux spécialiser partiellement le template pour le cas d'un paramètre vide.
Seulement, pour cela, je dois repeter tout le code en dehors du constructeur, ce qui entraîne des redondances.
Voilà, pour l'instant je m'y suis pris en réduisant au maximum le code restant du template InstanceOf<>, mais ca ne me convient toujours pas. Il doit y avoir une solution plus élegante, comme celle en D que j'ai postée plus haut.
Puis, pour ce qui est de la metaprogrammation avec if_<> ou enable_if<>, je n'arrive pas à saisir les exemples sur le site de boost, donc une explication plus en profondeur serait la bienvenue.
if_ ou enable_if permettent d'écire ou non un code selon la valeur d'un booléen statique membre d'une structure/classe.
Par contre, je viens de penser à une chose : et si tu utilisais une typelist ?
Tu mets ainsi autant de types que tu veux dedans, tu spécialises à ta guise.
Mon blog anglais - Mes articles et critiques de livres - FAQ C++0x, avec liste des nouveautés - Conseils sur le C++ - La meilleure FAQ du monde - Avant de créer des classes que vous réutiliserez, regardez si ça n'existe pas déjà - Le site du comité de normalisation du C++
Le guide pour bien débuter en C++ - Cours et tutoriels pour apprendre C++
boost/mpl/if.hpp:
Je comprend: boost::mpl::if_<true_,T1,T2>::type vaut T1 et boost::mpl:if_<false_,T1,T2>::type vaut T2. En aucun cas, j'ai du code en plus ou en moins!
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 template< bool C , typename T1 , typename T2 > struct if_c { typedef T1 type; }; template< typename T1 , typename T2 > struct if_c<false,T1,T2> { typedef T2 type; }; template< typename BOOST_MPL_AUX_NA_PARAM(T1) , typename BOOST_MPL_AUX_NA_PARAM(T2) , typename BOOST_MPL_AUX_NA_PARAM(T3) > struct if_ { private: typedef if_c< T1::value , T2 , T3 > almost_type_; public: typedef typename almost_type_::type type; };
De la même façon:
boost/enable_if.hpp:Ca me permet juste de choisir un type (if_) ou de vérifier un type (enable_if).
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10 template <bool B, class T = void> struct enable_if_c { typedef T type; }; template <class T> struct enable_if_c<false, T> {}; template <class Cond, class T = void> struct enable_if : public enable_if_c<Cond::value, T> {};
Ressources proposées par 3DArchi - Les fonctions virtuelles en C++ - Cours et tutoriels C++ - FAQ C++ - Forum C++.
ca me plaît comme idée (surtout que le paramètre unique touche rapidement ses limites...). Tu as plus d'infos dessus, ou du moins un lien qui explique le concept plus en détail?
tiens, une "solution" qui me permettrait de contourner presque le problème des redifinitions des templates partiellement spécialisé serait de m'écrire une petite macro preprocesseur avec Boost.pp qui irait me fournir une spécialisation totale du constructeur pour chaque classe s'en servant. C'est lourd vu que ca mélange le Preprocesseur et le compilateur (et la metacompilation sur chacun des deux), et ca me plaît pas trop, mais l'idée y est...
Et pour les typelists ?
Ca consiste à travailler sur une liste de types. Je te renvoie notamment vers Loki (http://loki-lib.sf.net/) et le bouquin associé (Modern C++ Design) pour en savoir plus.
Mon blog anglais - Mes articles et critiques de livres - FAQ C++0x, avec liste des nouveautés - Conseils sur le C++ - La meilleure FAQ du monde - Avant de créer des classes que vous réutiliserez, regardez si ça n'existe pas déjà - Le site du comité de normalisation du C++
Le guide pour bien débuter en C++ - Cours et tutoriels pour apprendre C++
Je connais Loki, je me sers du SingletonHolder<> pour mes singletons.
Vu que j'ai pas le bouquin d'Andrei Alexandrescu chez moi, tu peux m'en dire plus, notamment comment me servir du typelist dans mon exemple précis.
Ce petit test ne compile pas, et j'ai un gros doute de comment me servir du typelist.
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 //some compiler tests #include <loki/typelist.h> #include <loki/typemanip.h> using namespace Loki; using namespace Loki::TL; struct Bar0 { Bar0(){} }; struct Bar1 { float a; Bar1(float p):a(p){} }; struct Bar2 : Bar1 { int b; Bar2(float p0, int p1):Bar1(p0),b(p1){} }; //etc; template<class B, class Ty> struct Inter : B { template<int length> Inter(...); }; template<class B, class Ty> Inter<B, Ty>::Inter<0>(Ty):B(){} template<class B, class Ty> template<> Inter<B, Ty>::Inter<1>(TypeAt<Ty, 0>::Result p):B(p){} template<class B, class Ty> template<> Inter<B, Ty>::Inter<2>(TypeAt<Ty, 0>::Result p0, TypeAt<Ty, 1>::Result p1):B(p0, p1){} struct Foo0 : Inter< Bar0, void> { Foo0():Inter(){} }; struct Foo1 : Inter< Bar1, float> { Foo1(float i):Inter(i){} }; typedef MakeTypelist<float, int>::Result b2tl; struct Foo2 : Inter< Bar2, b2tl> { Foo2(float a, int b):Inter(a, b){} };
Je suppose que tu as fouillé toute la doc, les samples & compagnie ?![]()
Mon blog anglais - Mes articles et critiques de livres - FAQ C++0x, avec liste des nouveautés - Conseils sur le C++ - La meilleure FAQ du monde - Avant de créer des classes que vous réutiliserez, regardez si ça n'existe pas déjà - Le site du comité de normalisation du C++
Le guide pour bien débuter en C++ - Cours et tutoriels pour apprendre C++
Les typelists de Boost.MPL sont un peu un million de fois mieux que celles de Loki...
Ça se manipule exactement comme les conteneurs standard, sauf que c'est des conteneurs de types et que ça travaille avec des méta-fonctions au lieu de fonctions.
merci pour l'indice. D'ailleurs, j'ai trouvé Boost.Tuple qui correspond encore mieux à ce dont j'ai besoin. Et j'ai simplifié mon architecture, du coup j'ai pu déplacer ce problème dans une factory à part. Je posterai un peu de code demain.
Partager