Introduction

Many kudos to Jaakko Järvi, Don Clugston, Sergey Ryazanov, and others that have created really nice delegate libraries. I have spent many hours trying to decipher their implementations.

A recent project of mine was to create a network de-muxing framework in which new functionality could be readily added and invoked from the remote client. I thought delegates would be great here, and I realized that for the special case of invoking delegates where a parameter arbitrator class would be used, a slightly different method was needed than is available in many existing libraries.

In this article, I will explain this method. This is a specific case type delegate library, so it is not as general purpose as the other alternatives.

*Note: If you want to compile this on VC6, you will have to expand the macros.

Application Goals

We are going to create a delegate class that...

Is as simple and easy to follow as possible

Does not use dynamic memory allocation

Is pretty fast

Is Standard C++

Will require the use of an arbitrator class to pass parameters

The arbitrator class

What is an arbitrator class? An arbitrator class will hold the value of the parameter and convert to the correct type on the fly. Often, when data is coming from a serialized source such as a file or network connection, it is in an abstract form. To use this data as a parameter to a function, it must be converted to the proper type. The arbitrator class will handle this automatically. It will be up to the originator to ensure that the cast parameters actually make sense to the function.

This class is crafted to handle the situation of using abstract data as function parameters. It is also not necessary to know the number of parameters that a function requires, as this can be handled as a runtime error. This makes this delegate ideal for closing RPC calls.

Just as an example, we will use the _variant_t wrapper class from Microsoft as the Arbitrator. _variant_t simply holds an abstracted representation of a variable, and is able to cast to and from the concrete form. The TArbDelegate class I present here is really only appropriate if the parameters you intend to pass to the delegated functions are already in an abstract form.

How to use

Our delegates will be wrapped in a class named TArbDelegate. Before we jump into how the delegate class works, let's take a look at how it will be used.

You can see the use here is much like the use of a standard delegate. The only real difference is the use of the arbitrator for passing parameters. Notice also, that you do not need to specify the function signature.

How does it work?

First, let's look at a very simple version of the delegate class with all the macros and templates removed. This should make the basic idea much easier to see. This class will only handle functions returning a non-void value and taking two parameters. The actual class is a bit different since it handles multiple parameters and void return types.

Follow along with the comments, and let's let the code speak for itself.

It is the intention of the delegate class to decouple the C++ type checking. The CArbitrator class I provided here is only for demonstration. It is as you point out, and as I labeled it, naive.

This delegate class is not intended to be used as you have done here. You need a general case delegate for that. If you imagine this class being used to complete the circuit for a remote procedure call, it is appropriate. The C++ type checking can not infer function parameter types from a socket buffer after all

Care to explain the rationale behind the intention to decouple the C++ type checking and what benefits does it have?

I cannot imagine this class being used to complete the circuit for a remote procedure call, even for COM OLE automation, the VARIANT structure does store the type of the data, which is what you ought to do: If the types doesn't match, throw an exception, at least if you have no way of catching the mismatched types error at compile time, you catch it at runtime.

Edited: PS, I am not the one who voted one for this article, I don't know who did. I have not voted this article yet.

Care to explain the rationale behind the intention to decouple the C++ type checking and what benefits does it have?

If your going to make a call with abstracted data, you have to decouple the type checking. Explain to me how you would get the compiler to look into a serialized data format and see an 'int' for instance.

Wong Shao Voon wrote:

If the types doesn't match, throw an exception,

I agree, if the arbitration class noticed it was being cast to type int, and it held a string, it should throw an exception, or log an error, or whatever is appropriate. But again, this article isn't about the arbitrator.