On Wed, Mar 26, 2008 at 2:03 AM, Kevin Scarr <kscarr@iinet.net.au> wrote:
Steven Watanabe wrote:
> You might also look into replacing Packet with boost::variant.

I would second this. If you use:

typedef boost::variant<WalkPacket,CharPacket,etc> Packet;

You might also consider using pointers in your Packet type, or even
shared_ptr<WalkPacket>, etc, but that is a detail which depends on how
the rest of your application is built. I use pointer-like types because
I am very aware of making copies of my potentially-large and numerous
packets.

In this situation, all of your messaging infrastructure that deals with
packets passes around instances of the variant type.

As you have described, your clients have a mechanism where they can
register using wrapper functions around the signals library to receive
notification on the arrival of specific packet types - one signal for
each packet type.

When it comes time to distribute your packet, you can make use of the
boost::variant visitor feature, which allows you to select operations
based on the actual type of the data in your variant instance. In your
case it might look something like this:

// Your packet type
typedef boost::variant<WalkPacket,ChatPacket,etc> Packet;

// Your signals...
boost::signal<void (WalkerPacket)> distributeWalkerPacket;
boost::signal<void (ChatPacket)>   distributeChatPacket;

// Helper class for apply_visitor

class doDistributePacket : public static_visitor<>
{
public:

  void operator() ( WalkPacket p ) const
  {
    distributeWalkPacket( p );
  }

  void operator() ( ChatPacket p ) const
  {
    distributeChatPacket( p );
  }

// and so on ...
};

// Free function to drive this above.
void DistributePacket( Packet p )
{
  apply_visitor( doDistributePacket(), p );
}



I like boost::variant because it tends to bring all the type-dependent
code together and makes it easy to encapsulate type based decisions.

Kevin

I love the logic presented here. boost::variant has always been confusing to me, but I took the time just now to read over the documentation for it a few times and I get it now. However, the issue still remains in how to organize all of my signals. In your example you have all of the signals manually typed out into separate variables, whereas I would rather have them in some sort of container, such as a map. I couldn't put them in a std::map, since the value type is always required to be the same. I could use boost::tuple if I could guarantee that my packet ID's started at 0 and where contiguous thereafter (however the size limit of a tuple would be too small). Something like a tuple, except as a map would be a great solution. However since someone has already pretty much addressed that no such container exists, I'm still looking for clean alternatives. Consider that I may have 100 packet types (which is not unreasonable in the game we're working on), it would quickly become unmanageable to have 100 signal variables. Perhaps having 1 signal for all packets might be a good alternative, however I'd have to sit down and think about how it is going to work. Using 1 signal for all packets, as I pointed out before, really constrains the signature of the slots. Perhaps I should just send the boost::variant to my slots?

Thanks everyone for your continued help. You're really giving me some great ideas.