Texturant boost :: bind pour gérer automatiquement plusieurs arguments pour la fonction de membre
-
29-09-2019 - |
Question
J'ai une classe avec une fonction « Joindre » qui accepte un objet de fonction et la stocke dans une collection. La classe elle-même est templated sur la signature de la fonction. Quelque chose comme ceci:
template<class Signature>
class Event
{
public:
void Attach(boost::function<Signature> signature)
{
MySignatures.push_back(signature);
}
private:
std::list<boost::function<Signature>> MySignatures;
};
Pour démontrer l'utilisation, pensez à la classe suivante:
class Listening
{
public:
int SomeFunction(int x, int y, int z);
};
Pour passer la fonction sur Listening
dans Event
, il me faudrait écrire:
Event<int(int, int, int)> myEvent;
Listening myListening;
myEvent.Attach(boost::bind(boost::mem_fn(&Listening::SomeFunction), &myListening, _1, _2, _3));
Ainsi, au lieu de le faire pour chaque cas qui peut être sujette à l'erreur, j'écris un ensemble de macros, comme suit:
#define EventArgument0(x, y) boost::bind(boost::mem_fn(x), y)
#define EventArgument1(x, y) boost::bind(boost::mem_fn(x), y, _1)
#define EventArgument2(x, y) boost::bind(boost::mem_fn(x), y, _1, _2)
#define EventArgument3(x, y) boost::bind(boost::mem_fn(x), y, _1, _2, _3)
#define EventArgument4(x, y) boost::bind(boost::mem_fn(x), y, _1, _2, _3, _4)
etc.
et puis je peux écrire:
myEvent.Attach(EventArgument3(&Listening::SomeFunction, &myListening));
ce qui est beaucoup plus facile à lire (je pense). Maintenant, à ma question: comment puis-je écrire à la place:
myEvent.Attach(EventArgument(&Listening::SomeFunction, &MyListening));
ou mieux encore:
myEvent.Attach(&Listening::SomeFunction, &myListening);
, de sorte que l'événement attach sera correctement par magie se lier avec le nombre approprié d'arguments figurant dans int(int, int, int)
)? Je suis ouvert à toute la magie méta-programmation modèle que vous avez à l'esprit ici.
Merci.
Edit: il se trouve que je ne ai pas besoin boost::mem_fn
ici, parce que boost::bind
est équivalent, dans ma macro je peux utiliser:
bind(&MyClass::Hello, myClass, _1, _2, _3);
, au lieu de:
bind(mem_fn(&MyClass::Hello), myClass, _1, _2, _3);
La question reste cependant: comment passer &MyClass::Hello
au modèle classe d'événement et utiliser la surcharge pour gérer la _1
, _2
, _3
, etc. sous-entendus par le prototype de fonction utilisée à le modèle de la classe Event
La solution
Attach
surcharge pour des nombres différents de paramètres de la fonction de membre:
template<typename R,typename T,typename U>
void Attach(R (T::*pmf)(),U* p))
{
Attach(boost::bind(pmf,p));
}
template<typename R,typename T,typename U,typename A1>
void Attach(R (T::*pmf)(A1),U* p))
{
Attach(boost::bind(pmf,p,_1));
}
template<typename R,typename T,typename U,typename A1,typename A2>
void Attach(R (T::*pmf)(A1,A2),U* p))
{
Attach(boost::bind(pmf,p,_1,_2));
}
Si vous avez besoin pour gérer les fonctions membres de const
aussi vous aurez besoin d'un deuxième jeu de surcharges.
Autres conseils
Faire Attach()
un modèle vous permettra de faire ce que vous visez pour. Le code devient malpropre mais nous allons vous l'appelez comme vous le souhaitez.
template<typename A1>
void Attach(A1 a1);
template<typename A1, typename A2>
void Attach(A1 a1, A2 a2);
template<typename A1, typename A2, typename A3>
void Attach(A1 a1, A2 a2, A3 a3);
template<typename A1, typename A3, typename A4>
void Attach(A1 a1, A2 a2, A3 a3, A4 a4);