Search code examples
c++functor

How to implement delegates using functors and operator()


I've been trying to follow some of this advice:

https://softwareengineering.stackexchange.com/a/213635/46534
and
https://en.wikipedia.org/wiki/Function_object

But struggling to get it to compile.

I have a delegate definition:

struct SomeDelegate {
    void operator()(SomeType *data) {
        //do some stuff with data
    }
};

And then a member function which accepts a function pointer:

void DoSomethingThatCallsback(void(*callback)(SomeType *) ) {
    callback(ptrToSomeType);
}

And then when I try and use this member function as follows:

foo.DoSomethingThatCallsback(SomeDelegate());

I get the compile error:

cannot convert argument 1 from 'SomeDelegate' to 'void (__cdecl *)(Core::SomeType *)'

All the examples I've been reading suggest this is possible.

I've tried using templates like this:

template <typename Callback>
void DoSomethingThatCallsback(Callback callback)

But I get a similar error.

I'm ultimately looking for a more OOP approach to resorting to function pointers or moving to C++11. Also, unable to use the STL.

Updated with more context

struct MapOpenedDelegate {
public:

    void operator()(Map *openedMap) {

    }
};

class MapReader {
public:

    template <typename Callback>
    void RegisterMapOpenedCallback(Callback &callback) {
        _callbacks.Add(callback);
    }

private:
    Rise::List<void(*)(Map *)> _callbacks;
};
...
mapReader.RegisterMapOpenedCallback(MapOpenedDelegate());

Solution

  • The first approach doesn't work because you tell your function to accept a function pointer while you pass it a SomeDelegate instance.

    The template approach could indeed work, depending on the body of your template.

    Example of a template that could work:

    template <typename Callback>
    void DoSomethingThatCallsback(Callback& callback) {
      callback(ptrToSomeType);
    }
    

    Note that this works given that ptrToSomeType is of type SomeType*. And the Callback type equals the SomeDelegate type like you defined it in your question, or any other type that provides an operator() that accepts a SomeType* as its one and only argument.

    Update

    I think there's no real reason for using templates here, given what you provided me with now.

    First of all, in my previous answer I wasn't aware of the fact that these callback instances were to be stored in a list. This changes the situation completely.

    I've assumed in the below solution to your problem that the caller of the RegisterMapOpenedCallback has ownership of the callback instances. The caller passes them by reference and the MapReader only stores pointers to them.

    struct MapOpenedDelegate {
    public:
    
        void operator()(Map *openedMap) {
    
        }
    };
    
    class MapReader {
    public:
    
        void RegisterMapOpenedCallback(MapOpenedDelegate& callback) {
            _callbacks.Add(&callback);
        }
    
    private:
        Rise::List<MapOpenedDelegate*> _callbacks;
    };
    

    In order to provide a perfectly clear solution I still miss context. I'm not quite sure what you want to achieve other than storing some callback instances. I do hope that the above helps you in some way though.