The SRUtil.Delegate library contains yet another C++ delegates implementation and delegate invokers. Delegate is an object oriented analogue of a function pointer. Unlike a function pointer it can refer to both an object and its method with an appropriate signature. A delegate is more flexible than a virtual method and a pointer to method because invocation code doesn't depend on type of the object.
A delegate is particular case of boost::function, but essentially more efficient.
Invoker allows to bind arguments and invoke any functor (including a delegate) with them.
This implementation achieves the following goals:
SRUtil.Delegate has two syntaxical forms: the preferred form and the portable form. Preferred form is more readable, but is not supported on all platforms due to compiler bugs.
A delegate is defined by instantiating the delegate class template with the return type and argument types. The following declares a delegate which takes two integer parameters and retuns a float:
Preferred syntax | Portable syntax |
---|---|
srutil::delegate<float
(int,
int)> d; |
srutil::delegate2<float,
int,
int> d; |
By default, a delegates is empty. Invocation of such delegate usually leads to
access violation. You can test a state of the delegate by implicit casting to
boolean type or using operator '!
', for example:
if (d)
std::cout
<< "the delegate is empty\n";
if (!d)
std::cout << "the delegate is not empty\n";
To construct a nonempty delegate you should use one of following methods:
void f(int, int);
class SomeClass
{
public:
void m1(int, int);
void m2(int) const;
static void m3(int, int);
};
typedef srutil::delegate<void (int, int )> Delegate;
d = Delegate::from_function<&f>();
d = Delegate::from_method<SomeClass, &SomeClass::m1>();
d = Delegate::from_const_method<SomeClass, &SomeClass::m2>();
d = Delegate::from_function<&SomeClass::m3>();
To invoke you should use function call operator:
d(10, 20);
Also you can get an appropriate type of invoker:
Delegate::invoker_type i(10, 20);
i(d);
In current implementation you can't bind delegates with function which has nonstandard modificators.
The delegate binds with a target method at compile time. You can't bind the delegate with method if its address is known only at runtime.
Delegates may not be compared. It means you can't use C# style like for events subscribing and unsubscribing. Instead you can use SRUtil.Event library.
Invokers are designed to simplify using the delegates, but may be used with any functor.
As well as delegates invokers have two syntaxes:
Preferred syntax | Portable syntax |
---|---|
srutil::invoker<float
(int,
int)> d; |
srutil::invoker2<float,
int,
int> d; |
Invokers bind arguments in constructor and pass it into a functor:
void functor(int, int);
srutil::invoker<void (int, int)> i(10, 20);
i(&functor); // equal to functor(10, 20);