passer un objet appelable à une fonction membre
Question
class Action {
public:
void operator() () const;
}
class Data {
public:
Data();
~Data();
Register(Action action) { _a = action; }
private:
Action _a;
}
class Display {
public:
Display(Data d) { d.Register( bind(Display::SomeTask, this, _1) ); }
~Display();
void SomeTask();
}
Je veux lier le député _A des données à une fonction de membre d'affichage, mais je reçois des erreurs de compilation en disant mes types d'arguments ne correspondent pas quand je l'appelle d.Register, qu'est-ce que je fais mal? Merci.
La solution
Qu'est-ce que vous essayez de faire est pas tout à fait clair, mais je suppose que "lier" est boost :: bind (ou TR1 :: bind).
Un couple de problèmes avec bind (affichage :: SomeTask, ce, _1):
- Il devrait être & Display :: SomeTask
- L'espace réservé _1 n'a pas de sens, car cela crée un objet de fonction unaire et:
- Affichage :: SomeTask ne prend aucun argument
- Action opérateur :: () ne prend aucun argument
Utilisation Boost.Function et Boost.Bind, voici ce que vous pouvez écrire à acheive ce que je suppose que vous essayez de faire:
typedef boost::function<void(void)> Action;
class Data {
public:
Data();
~Data();
Register(Action action) { _a = action; }
private:
Action _a;
};
class Display {
public:
Display(Data d) { d.Register( bind(&Display::SomeTask, this) ); }
~Display();
void SomeTask();
};
Autres conseils
Je ne vois pas ce que « lier » les retours, mais je suis absolument sûr que ce n'est pas compatible avec la classe d'action. vous utilisez également « copie sémantique », donc si l'action a implmentation vide, vous ne serez jamais désiré. Essayez changer de registre (Action d'action *), et permettre à « lier » pour revenir un enfant de la classe d'action.
Consultez également la possibilité de migrer vers des modèles - que vous pouvez même exclure la classe d'action du tout
template <class A>
class Data { ...
Register(A action)...
A _a;
...
Dans ce cas, vous pourriez être en mesure d'utiliser comme classes avec opérateur () redéfinie comme fonctions sans argument.
D'abord, vous devez utiliser &Display::SomeTask
et donner Register
un type de retour, et il dépend de vos besoins
- L'emballage doit appeler
SomeTask
sur*this
: Omettre_1
. - L'emballage doit appeler
SomeTask
sur un objetDisplay
passé: Shift_1
à la place dethis
.
Ensuite, boost::bind
retourne un certain type de synthèse complexe qui appelle la fonction spécifiée. Vous avez besoin d'un moyen de stocker, ce qui est à portée de main où boost::function
vient. Voici comment vous pouvez le faire
class Display; // forward-declaration
class Data {
public:
Data();
~Data();
template<typename Action>
void Register(Action action) { _a = action; }
private:
boost::function<void(Display&)> _a;
// if wrapper should call it on `*this`
// boost::function<void()> _a;
}
class Display {
public:
// this currently makes no sense. You pass a copy. Probably you
// should consider pass-by-reference or processing "d" further.
Display(Data d) { d.Register( bind(&Display::SomeTask, _1) ); }
// wrapper should call it on `*this`:
// Display(Data d) { d.Register( bind(&Display::SomeTask, this) ); }
~Display();
void SomeTask();
}
Ensuite, il devrait fonctionner.