C++11 - Delegate class

Hi, folks!

Since we have had these nice C++11 features laying around here some time I decided to use those great new features to implement a simple delegate class.

My main goal is elegance and efficiently. I want the interface to like this:

1
2
3
Delegate<int (int)> delegate;
delegate.bind(&f); // For static member functions.
delegate.bind<C>(c, &C::f); // For member functions. 


And here's the implementation (excluding specializations):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
template<typename Return, typename Parameter, typename... Parameters>
class Delegate<Return (Parameter, Parameters...)>{
public:

    /// Constructors & destructors:
    Delegate(void) : _m_fpFunc(nullptr), _m_voidpInstance(nullptr){

    }
    Delegate(Delegate const& delegate) = default;
    Delegate(Delegate&& delegate) = default;

    /// Member functions:
    template<Return (*Function)(Parameter, Parameters...)>
    Delegate& bind(void){
        _m_fpFunc = &_get_function_static<Function>;
        _m_voidpInstance = nullptr;
        return *this;
    }
    template<class C, Return (C::*Function)(Parameter, Parameters...)>
    Delegate& bind(C& c){
        _m_fpFunc = &_get_function_member<C, Function>;
        _m_voidpInstance = &c;
        return *this;
    }
    inline bool bound(void) const{
        return (_m_fpFunc != nullptr);
    }

    /// Member functions (overloaded operators):
    inline Return operator()(Parameter param, Parameters... params) const{
        return _m_fpFunc(_m_voidpInstance, param, params...);
    }

private:
    /// Member data:
    Return (*_m_fpFunc)(void*, Parameter, Parameters...);
    void* _m_voidpInstance;
    /// Static member functions:
    template<class C, Return (C::*Function)(Parameter, Parameters...)>
    static inline Return _get_function_member(void* instance, Parameter param, Parameters... params){
        return (static_cast<C*>(instance)->*Function)(param, params...);
    }
    template<Return (*Function)(Parameter, Parameters...)>
    static inline Return _get_function_static(void*, Parameter param, Parameters... params){
        return (Function)(param, params...);
    }
};


If try to use this delegate class, you'll see that the only ways bind-functions can be used are as follows:

1
2
delegate.bind<&f>(); // For static member functions.
delegate.bind<C, &C::f>(c); // For member functions. 


You'll see it's not the most awkward method call ever, but compared to this

1
2
3
Delegate<int (int)> delegate;
delegate.bind(&f); // For static member functions.
delegate.bind<C>(c, &C::f); // For member functions. 


it's not that great.

Then it hit me - decltype. Thank you God, this will help me out! Let's try this:

1
2
3
4
5
6
7
8
9
10
11
12
/// Member functions:
Delegate& bind(Return (*function)(Parameter, Parameters...)){
    _m_fpFunc = &_get_function_static<decltype(function)>;
    _m_voidpInstance = nullptr;
    return *this;
}
template<class C>
Delegate& bind(C& c, Return (C::*function)(Parameter, Parameters...)){
    _m_fpFunc = &_get_function_member<C, decltype(function)>;
    _m_voidpInstance = &c;
    return *this;
}


But guess what, it doesn't work! Why!? What's going on?
std::function and std::bind in the <functional> header already do all of this. Any reason why you don't want to just use those?
I've heard about them. How's the syntax with those?

PS: Still want to figure why my decltype doesn't work.
Last edited on
I've heard about them. How's the syntax with those?


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <functional>

class AClass
{
public:
    static int stat( int );

    int oneparam( int );
    int noparam(  );
    int twoparam( int, int );

};

int main()
{
    AClass obj;

    std::function< int(int) > f;
    
    f = std::bind( &AClass::stat, std::placeholders::_1 );
    f(1);  // calls     AClass::stat(1)


    f = std::bind( &AClass::oneparam, &obj, std::placeholders::_1 );
    f(1);  // calls     obj.oneparam(1)

    f = std::bind( &AClass::noparam, &obj );
    f(1);  // calls     obj.noparam()

    f = std::bind( &AClass::twoparam, &obj, 5, std::placeholders::_1 );
    f(1);  // calls     obj.twoparam( 5, 1 )
}
Thanks for the piece of code. One thing bugs me though:

1
2
f = std::bind( &AClass::twoparam, &obj, 5, std::placeholders::_1 );
f(1);  // calls     obj.twoparam( 5, 1 ) 


Why isn't it f(5, 1)?
Because 'f' is a int(int) functor (ie: it only takes 1 param).

AClass::twoparam takes 2 parameters, so it doesn't quite fit the int(int) signature. Here, bind "fills in" the extra parameter.
Because 'f' is a int(int) functor (ie: it only takes 1 param).

AClass::twoparam takes 2 parameters, so it doesn't quite fit the int(int) signature. Here, bind "fills in" the extra parameter.


Doesn't sound that comfortable. I'll try to go on with my delegate implementation, if you don't mind! :-)
Doesn't sound that comfortable. I'll try to go on with my delegate implementation, if you don't mind!


I don't mind at all. But I'm curious as to how you'd approach it differently. My understanding of variatic arguments is admittedly lacking, so I'm not quite sure I fully understand the usage of the code you posted.
Topic archived. No new replies allowed.