2010-08-19 3 views
3

J'ai une classe avec une fonction "Attach" qui accepte un objet fonction et le stocke dans une collection. La classe elle-même est modélisée sur la signature de la fonction. Quelque chose comme ceci:Mappage boost :: bind pour gérer automatiquement plusieurs arguments pour la fonction membre

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 en 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)); 

Alors au lieu de le faire pour chaque cas qui peut être sujet à 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 je peux écrire:


myEvent.Attach(EventArgument3(&Listening::SomeFunction, &myListening)); 

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 lier par magie avec le nombre approprié d'arguments figurant dans < Signature > (dans cet exemple, int(int, int, int))? Je suis ouvert à n'importe quel modèle de magie de méta-programmation que vous avez en tête 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 à la classe d'événement et utiliser la surcharge de modèle pour gérer le _1, _2, _3, etc. implicite par le prototype de la fonction utilisée pour modéliser le Event classe?

+0

Avez-vous essayé Google/Bing pour "transfert parfait"? En supposant que vous pouvez utiliser C++ 0x. – Henrik

+0

Je le regarde maintenant, par exemple ici: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2002/n1385.htm. Ce n'est pas clair pour moi comment cela aide à résoudre le problème. – Robinson

Répondre

2

surcharge Attach pour différents nombres de paramètres dans la fonction 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 const membres aussi vous aurez besoin d'un deuxième ensemble de surcharges.

+0

Brillant. Je l'ai légèrement modifié pour fonctionner avec shared_ptr (donc je peux contenir des références weak_ptr et abandonner des pointeurs .expired() avant de déclencher l'événement). Sinon, c'est une excellente solution. Merci. – Robinson

2

Faire un Attach() un modèle vous permettrait de faire ce que vous visez. Le code devient en désordre mais il vous permet de l'appeler 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); 
Questions connexes