2

Currently trying to implement an event handler for an SDL project. The general idea is that user input events will be handled via Message objects, that will be able to carry around callbacks with different signatures.Currently, what I have is :

#pragma once
#include<functional>

#include"Entity.h"
#include"Enums.h"

typedef std::function<void(void)> VoidCallback;
typedef std::function<void(const Entity& entity)> EntityCallback;

template<typename Functor>
class Message
{
private:
    MessageType message;

public:
    Message(MessageType message, Functor callback) :message(message), callback(callback) {};
    ~Message();
};

However, this arrangement makes it difficult to pass different types of callbacks to different listeners. The current listener implementation is

#include"Message.h"

class Listener
{
public:
    virtual void onNotify(Message<>& event) = 0;
};

which which causes errors. What would be the best way to resolve this issue?

  • 1
    You `Message` template *must* have its template parameter, without it you will indeed get a lot of errors. Perhaps this could be solved through inheritance and polymorhpism instead? With a base-class having a pure abstract "call" function (or similar) that is called by `Listener::onNotify`? – Some programmer dude Jun 25 '18 at 19:10
  • @Someprogrammerdude That would provide a simpler fix, but trying to figure out templates :) – Willbur Smith Jun 25 '18 at 19:15
  • 1
    Why does a message have a functor in it? Why does the template `Message` class have a `Functor` argument, then never use it, yet use `MessageType` which is undefined? About the only thing I understand about your question is "I want to use callbacks and listeners, but I have no idea how any of it works". Can you be more clear? – Yakk - Adam Nevraumont Jun 25 '18 at 19:15
  • How can a callback have different signatures? Who will call that and how would the caller know which parameters have to be present. This all looks for me as an XY problem. If you need a callback with different parameters you have a design problem, independent how to solve it. – Klaus Jun 25 '18 at 20:02

2 Answers2

1

You cannot have a template virtual function

Can a C++ class member function template be virtual?

#include "Message.h"

class Listener
{
public:

    //you may use a template function as such
    template<class func>
    void onNotify(Message<func>& event) { /*must implement*/ }

    //or specialize for specific function calls
    virtual void onNotify(Message<some_known_func>& even) = 0;
};

If you want to utilize template-methods with a virtual-like features you may be interested in looking into CRTP. (CRTP enables the super-class to call the subclasses methods)

Joseph D.
  • 11,804
  • 3
  • 34
  • 67
1

It is not possible for a virtual function to be templated.

Virtual function are called through a vtable, which is basically an array of function pointer. Each virtual method in a base class takes up a slot in the virtual table. Obviously the virtual table size needs to be known at compile time, because it is part of the object definition.

class Base {
public:
    virtual void hello(){};
    virtual void bye(){};   
}

The vtable could look like this:

  • Pointer to hello.
  • Pointer to bye.

So the vtable needs 2 functions pointer.

Now if either hello() or bye() were to be templated, how could we create a vtable?

  • Pointer to hello<int>()
  • Pointer to hello<char>().

We cannot know in advance all the variation of the templated function so it's not possible to build a vtable.

Joseph D.
  • 11,804
  • 3
  • 34
  • 67
Xaqq
  • 4,308
  • 2
  • 25
  • 38