Pour votre première question: Je ne suis pas au courant d'un «moyen standard boost» pour réaliser ce que vous voulez. Vous pouvez poster votre question au boost users mailing list.
Pour votre deuxième question: Sans modèles varidiques et références rvalue, le transfert est toujours fastidieux.
Quelques suggestions, sans ordre particulier:
1) Vous pouvez regarder le coup de pouce/signal.hpp et les fichiers Boost/signaux/pour avoir une idée de la façon dont ce genre de choses peut être fait avec le préprocesseur, mais voici une mise en œuvre partielle pour montrer l'idée (avertissement: non testé):
template<size_t Arity, class SignalT>
struct SlotBase;
template<class SignalT>
struct SlotBase<0, SignalT>
{
typedef SignalT::slot_function_type SlotType;
SlotBase(boost::shared_ptr<SignalT> S, SlotType F)
: m_Signal(S), m_Connection(S->connect(F))){};
void operator()()const
{
m_Connection.block();
m_Signal();
m_Connection.unblock()
};
private:
boost::shared_ptr<SignalT> > m_Signal;
boost::signals::connection m_Connection;
};
template<class SignalT>
struct SlotBase<1, SignalT>
{
// as above, except for operator()
// ...
void operator()(typename SignalT::arg1_type arg1)
{
m_Connection.block();
m_Signal(arg1);
m_Connection.unblock();
};
};
template<class SignalT>
struct SlotBase<2, SignalT>
{
// as above, except for operator()
// ...
void operator()(typename SignalT::arg1_type arg1, typename SignalT::arg2_type arg2)
{
m_Connection.block();
m_Signal(arg1, arg2);
m_Connection.unblock()
};
};
// repeat for other arities
// ...
template<class SignalT>
class SlotObject : public SlotBase<SignalT::arity, SignalT>
{
typedef SlotBase<SignalT::arity, SignalT> BaseType;
public:
Slot(boost::shared_ptr<SignalT>S,
typename SignalT::slot_function_type F
) : BaseType(S, F)
{}
};
2) Si vous êtes prêt à abandonner un peu de syntaxe nicety pour les utilisateurs de SlotObject, d'autres choses sont possibles. L'une consiste à enrouler l'appel sur le signal en utilisant la technique indiquée dans la documentation boost :: shared_ptr (http://www.boost.org/doc/libs/1_40_0/libs/smart_ptr/sp_techniques.html#wrapper), c.-à-d. Que votre méthode Call() bloque la connexion m_signal, et renvoie un shared_ptr à m_signal ayant un suppresseur personnalisé qui débloque m_connection. Malheureusement, cela ne donne pas une bonne syntaxe à l'appelant. Il ressemblerait à ceci:
SlotObject<signal<void(int, float)> > s = ...;
s.Call()->operator()(1, 1.234);
3) Une autre alternative est de demander à l'utilisateur de regrouper les arguments dans un tuple (j'utilise un boost::fusion::vector ci-dessous) sur le site d'appel, et utilisez boost::fusion:::fused pour les déballer et appelez le signal.
#include <boost/function_types/parameter_types.hpp>
#include <boost/fusion/include/vector.hpp>
#include <boost/fusion/include/mpl.hpp>
#include <boost/fusion/include/fused.hpp>
#include <boost/signal.hpp>
#include <boost/shared_ptr.hpp>
// Metafunction to extract the Signature template parameter
// from a boost::signal instantiation
// For example, SignatureOf<signal<void(int, float)>::type
// is "void(int, float)"
template<class SignalT>
struct SignatureOf;
template<
typename Signature, typename Combiner, typename Group,
typename GroupCompare, typename SlotFunction
>
struct SignatureOf<
boost::signal<Signature, Combiner, Group, GroupCompare, SlotFunction>
>
{
typedef Signature type;
};
// The SlotObject
template<class SignalT>
class SlotObject
{
public:
typedef typename SignatureOf<SignalT>::type SignatureType;
// Defines the "packed" parameters type corresponding
// to the slot's signature
// For example, for a SignalT of boost::signal<void(int, float)>
// ArgsType is "boost::fusion::vector<int, float>"
typedef typename boost::fusion::result_of::as_vector<
typename boost::function_types::parameter_types<SignatureType>::type
>::type ArgsType;
void Call(ArgsType P)
{
m_Connection.block();
boost::fusion::fused<SignalT&> f(*m_Signal);
f(P);
m_Connection.unblock();
}
//...
};
Ce serait utilisé comme:
typedef SlotObject<boost::signal<void(int, float)> > SlotType;
SlotType s = ...;
s.Call(SlotType::ArgsType(1, "foo"));
Je ne comprends pas ce que vous essayez d'atteindre. Dans votre exemple, la connexion appartient à SlotObject, donc le seul cas d'utilisation que je vois pour block() dans Call() serait d'annuler la récursivité, c'est-à-dire que slot() appelle SlotObject :: Call(). Est-ce le cas? –
J'essaie de synchroniser l'ajout d'éléments entre plusieurs objets. Chaque objet peut ajouter des éléments et envoyer des notifications à tous les autres. C'est à dire. le slot n'est pas Call(). Call() est nécessaire pour envoyer des notifications à tous les objets sauf le propriétaire. Je sais qu'il peut être mis en œuvre par des moyens plus simples, juste s'interroger sur la syntaxe. – Eugene