Foncteurs polymorphes dans std :: for_each
-
03-07-2019 - |
Question
J'essaie d'utiliser l'algorithme stl pour_each sans multiplier les modèles dans tout mon code. std :: for_each veut instancier la classe MyFunctor par valeur, mais ne le peut pas depuis son résumé. J'ai créé une classe d'adaptateur de foncteur qui fait passer un pointeur puis le neutralise le cas échéant.
Ma question:
La STL ou Boost a-t-elle déjà une telle classe d’adaptateur? Je ne veux pas avoir à réinventer la roue!
struct MyFunctor {
virtual ~MyFunctor() {}
virtual void operator()(int a) = 0;
}
namespace {
template<typename FunctorType, typename OperandType> struct
FunctorAdapter
{
FunctorAdapter(FunctorType* functor) : mFunctor(functor) {}
void operator()(OperandType& subject)
{
(*mFunctor)(subject);
}
FunctorType* mFunctor;
}; }
void applyToAll(MyFunctor &f) {
FunctorHelper<MyFunctor, int> tmp(&f);
std::for_each(myvector.begin(), myvector.end(), tmp); }
A bientôt,
Dave
La solution
tr1 :: ref peut vous aider ici --- il est censé être un wrapper de référence afin que vous puissiez transmettre des objets normaux par référence à des objets de liaison ou de fonction (même des objets abstraits) en vous référant à des algorithmes standard.
// requires TR1 support from your compiler / standard library implementation
#include <functional>
void applyToAll(MyFunctor &f) {
std::for_each(
myvector.begin(),
myvector.end(),
std::tr1::ref(f)
);
}
Cependant, notez que les compilateurs sans decltype prennent en charge PEUVENT refuser de transmettre une référence à un type abstrait ... afin que ce code ne puisse pas être compilé tant que vous n'avez pas pris en charge C ++ 0x.
Autres conseils
Vous pouvez utiliser les adaptateurs de fonction (et leurs cales) à partir de fonctionnel
.
#include <functional>
using namespace std;
for_each( vec.begin(), vec.end(), :mem_fun_ptr( &MyClass::f ) );
Si votre conteneur contient des pointeurs sur des objets, utilisez mem_fun_ptr
, sinon utilisez mem_fun
. A côté de ceux-ci, il y a des wrappers pour les fonctions membres qui prennent un argument: mem_fun1_ptr
et mem_fun1
.
@Evan: vous pouvez en effet appeler la fonction membre avec le même argument pour chaque objet. Le premier argument des wrappers mem_fun1
est le pointeur this
, le second est l'argument de la fonction membre:
for_each( vec.begin(), vec.end(), bind2nd( mem_fun_ptr( &MyClass::f ), 1 ) );
Avec plus d'arguments, il devient plus lisible de créer une boucle vous-même ou de créer un foncteur personnalisé comportant des variables de membre const représentant les arguments.
pourquoi ne pas utiliser BOOST_FOREACH?
Il semblerait que vous puissiez tirer parti de Boost :: Function .
Si je me souviens bien, c'est aussi une bibliothèque contenant uniquement un en-tête, il est donc facile de le faire fonctionner.
Pourquoi ne pas oublier l’habillage du pointeur du foncteur et utiliser à la place
bind (functor_pointer, mem_fun1 (& MyFunctor :: operator ());
en tant que foncteur? De cette façon, vous n’aurez plus à vous soucier de la gestion de la copie.
Construire sur la réponse de @ xtofl, car le tableau contient les int et pas "this" pointeurs, je pense que la bonne incantation est
class MyClass
{
virtual void process(int number) = 0;
};
MyClass *instance = ...;
for_each( vec.begin(), vec.end(), binder1st(instance, mem_fun_ptr(&MyClass::process) );
La seule différence par rapport au code de @ xtofl est binder1st plutôt que binder2nd. binder2nd vous permet de transmettre le même numéro à plusieurs "ceci". pointeurs. binder1st vous permet de passer différents numéros à un "ceci". pointeur.