Bonjour à tous,
J'ai écrit un foncteur générique qui permet de créer facilement un foncteur de comparaison à utiliser dans std::set ou std::map en écrivant le moins de code possible :
On l'utilise alors comme suit :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6 template<typename T, typename I, I (T::*F)() const> struct mem_fun_comp_t { bool operator () (const T& t1, const T& t2) const { return (t1.*F)() < (t2.*F)(); } };
Le problème est qu'on doit fournir deux informations redondantes en paramètres de mem_fun_comp_t : la classe test d'une part, et le type de la valeur comparée (const std::string& ou int) d'autre part, qui font toute deux partie de la signature de la fonction membre passée en troisième paramètre.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13 // classe de test struct test { const std::string name_; const int id_; const std::string& name() const { return name_; } int id() const { return id_; } }; // 's1' est trié selon 'name' std::set<test, mem_fun_comp_t<test, const std::string&, &test::name>> s1; // 's2' est trié selon 'id' std::set<test, mem_fun_comp_t<test, int, &test::id>> s2;
Je cherche donc un moyen d'éviter cette lourdeur. La seule solution que j'ai trouvée jusqu'à présent, et que je n'aime pas trop, est de recourir à une macro :
On l'utilise alors comme ceci :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10 // extraire la classe qui possède la fonction membre template<typename T, typename I> T mem_fun_owner(I (T::*f)() const) { return std::declval<T>(); } // extraire le type de la valeur comparée template<typename T, typename I> I mem_fun_return_type(I (T::*f)() const) { return std::declval<I>(); } // la macro #define mem_fun_comp(f) mem_fun_comp_t<decltype(mem_fun_owner(f)), decltype(mem_fun_return_type(f)), f>
Voyez-vous une autre solution qui n'utilise pas de macro ?
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4 // 's1' est trié selon 'name' std::set<test, mem_fun_comp(&test::name)> s1; // 's2' est trié selon 'id' std::set<test, mem_fun_comp(&test::id)> s2;
HS : ce qui est sympa, c'est qu'on peut écrire quelque chose de très similaire pour trier selon une variable membre, sans avoir besoin de définir un accesseur (à condition que cette variable soit publique, bien entendu) :
Ça m'a fait découvrir pour la première fois une utilité aux pointeurs sur variables membres
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 template<typename T, typename I, I T::*V> struct mem_var_comp_t { bool operator () (const T& t1, const T& t2) const { return t1.*V < t2.*V; } }; template<typename T, typename I> T mem_var_owner(I T::* v) { return std::declval<T>(); } template<typename T, typename I> I mem_var_type(I T::* v) { return std::declval<I>(); } #define mem_var_comp(v) mem_var_comp_t<decltype(mem_var_owner(v)), decltype(mem_var_type(v)), v> // 's1' est trié selon 'name' std::set<test, mem_var_comp(&test::name_)> s1; // 's2' est trié selon 'id' std::set<test, mem_var_comp(&test::id_)> s2;
Partager