On Fri, Mar 28, 2008 at 1:03 PM, Steven Watanabe <watanabesj@gmail.com> wrote:
AMDG

Robert Dailey wrote:
> Subscription doesn't seem as simple as you proposed. I looked into
> possible designs for subscribing to the signals and nothing is working
> out. There's no way to generate a second map to provide slot
> connections, since the signal object is actually owned by the first
> map, and thus the two cannot share them. Secondly, the slots (given
> the design above) each have a different signature for each packet,
> which further complicates things.
>
> Any suggestions? I'm having trouble thinking outside the box...

#include <boost/signal.hpp>
#include <boost/function.hpp>
#include <boost/unordered_map.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/mpl/integral_c.hpp>
#include <vector>
#include <utility>
#include <iostream>

struct Packet {};

struct WalkPacket : Packet {};

enum PacketID {
   PID_WALKPACKET
};

template<class T>
struct GetPacketID;

template<>
struct GetPacketID<WalkPacket> : boost::mpl::integral_c<PacketID,
PID_WALKPACKET> {};

template<class T>
struct StaticCaster {
   StaticCaster(boost::shared_ptr<boost::signal<void(T const&)> >
const& signal) : signal(signal) {}
   boost::shared_ptr<boost::signal<void(T const&)> > signal;
   void operator()(Packet const& packet) const {
       (*signal)(static_cast<T const&>(packet));
   }
};

class SignalHolder {
public:
   template<class T, class F>
   void register_function(F f) {
       const PacketID id = GetPacketID<T>::value;
       dispatcher_t::iterator iter = dispatcher.find(id);
       if(iter == dispatcher.end()) {
           boost::shared_ptr<boost::signal<void(T const&)> > signal(new
boost::signal<void(T const&)>());
           iter = dispatcher.insert(std::make_pair(id,
std::make_pair(static_cast<boost::shared_ptr<void> >(signal),
StaticCaster<T>(signal)))).first;
       }
       boost::static_pointer_cast<boost::signal<void(T const&)>
 >(iter->second.first)->connect(f);
   };
   void operator()(PacketID id, const Packet& packet) {
       dispatcher[id].second(packet);
   }
private:
   typedef boost::unordered_map<PacketID,
std::pair<boost::shared_ptr<void>, boost::function<void(Packet const&)>
 > > dispatcher_t;
   dispatcher_t dispatcher;
};

void test(WalkPacket const&) {
   std::cout << "Got a WalkPacket" << std::endl;
}

int main() {

   SignalHolder holder;

   holder.register_function<WalkPacket>(&test);

   WalkPacket packet;

   holder(PID_WALKPACKET, packet);
}

In Christ,
Steven Watanabe

Thanks, this is a great idea. However, while you're doing the insert() I noticed you're using statc_cast<>(). I'm actually surprised this compiles. This is basically like casting something to an unrelated type, so I'm not sure how the compiler is allowing this behavior. This also seems very inconsistent in that you're using boost::static_pointer_cast() for going from basically a void* to a signal object.