Bonjour à tous,
J'ai vu que beaucoup de classes de type_traits suivaient l'idée d'une classe A héritant de B, et de spécialisations de classe A héritant de C (B et C étant boost::true_type et boost::false_type, et A étant par exemple is_integer).
L'idée étant de définir, dans une fonction générique FONC<T>, un appel à la fonction CALL( A<T> ), qui invoque l'une des deux surcharges CALL( B ) ou CALL( C ) selon la valeur de T. On trouve un exemple ici.
Pour clarifier, j'ai le sentiment que l'idée générale est de faire :
Ma question est : je suis géné par le fait d'utiliser une surcharge "classique" par paramètre, où une spécialisation de template suffirait. Il suffirait alors de définir A::type (comme le fait add_const, etc.) en fonction du template de A, et d'invoquer CALL<A::type>() au lieu de CALL( A::type() ). Pour être plus clair, cela voudrait dire faire :
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 #include <iostream> struct True {}; struct False {}; template <class T> struct IsInt : public False {}; template <> struct IsInt <int> : public True {}; void Fonc( False const& ) { std::cout << "Is not signed int\n"; } void Fonc( True const& ) { std::cout << "Is signed int\n"; } template <class T> void Do( void ) { Fonc( IsInt<T>() ); }
Cela me semble plus correct, et ça m'a l'air aussi plus performant : j'ai regardé les instructions ASM générées par g++ -O2, et le premier bout de code passe un argument à Fonc(), même si cet argument n'est pas utilisé (-> il rajoute une instruction "lea ...").
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 #include <iostream> struct True {}; struct False {}; template <class T> struct IsInt { typedef False type; }; template <> struct IsInt <int> { typedef True type; }; template <class T> void Fonc( void ) { std::cout << "Is not signed int\n"; } template <> void Fonc<True>( void ) { std::cout << "Is signed int\n"; } template <class T> void Do( void ) { Fonc<typename IsInt<T>::type>(); }
Mais j'aimerais avoir votre idée sur la question :
- qu'en pensez-vous ?
- est-il possible d'éviter une surcharge paramétrique dans un tel cas avec boost::is_integer ou struct similaire ?
Merci beaucoup
Edit : je viens de penser à cette autre solution :
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 #include <iostream> #include <boost/type_traits.hpp> template <class T> struct IsInt : public boost::false_type {}; template <> struct IsInt <int> : public boost::true_type {}; template <bool> void Fonc( void ) { std::cout << "Is not signed int\n"; } template <> void Fonc<true>( void ) { std::cout << "Is signed int\n"; } template <class T> void Do( void ) { Fonc<IsInt<T>::value>(); }
Partager