"virtual template function"

Hey there,

So... yeah, I've been working on a "state mashine library" and worked with event-tables up until now.

Now I've packed all those things up in a few classes to make it "prettier" or more confortable to use and extend.

This is what it looks like at the moment.

I have a base-class for events.
I want to distinguish what type of event it is so I made... a not so pretty work around with an enum that contains all Events and made the base class a template-class. (please tell me if you have a better Idea for that task)

Then I have a base class for screens.
This is an abstract class with a default implementation of each single event-method.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
enum { Button1, Button2, Timer1, Timer2, N_EVENTS };
template <unsigned int event_id>
struct IEvent
{
};

IEvent<Button1> button1;
IEvent<Button2> button2;
IEvent<Timer1> timer1;
IEvent<Timer2> timer2;


// Base State
struct AState
{
public:
	virtual void Enter() = 0;
	virtual void Leave() = 0;

	virtual void Event(const IEvent<Button1>&) {}
	virtual void Event(const IEvent<Button2>&) {}
	virtual void Event(const IEvent<Timer1>&) {}
	virtual void Event(const IEvent<Timer2>&) {}
};

This is what it looks like in use: http://cpp.sh/5ykb

So, I realized that, everytime I implement a new event, I have to change the AState base class.
To avoid that I'd like use something like a virtual template function
1
2
template <unsigned int event_id>
virtual void Event(const IEvent<event_id>&) {}


Is it possible to do it this way?
Is there a better alternative to make my EventTypes? (I really don't like to rely on an enumeration for my Types)
Is there an other way to default-implement the Event Mehtods?
(The Methods should do nothing if they are not declared in the derived class)

Well, that's about everything, I hope someone can help me :)

- Gamer2015
You are basically asking: how do I add a new event without writing any code?

Sorry, you have to write code. However, you do have multiple options for how to do that:
- You can stick with your current implementation (which is kind of weird, but whatever)
- You can make a separate class to derive from for each new event (this is what I personally do, but with templates)
- You could go back to the stone ages and use an enum (like SFML)

For the second option, remember that template classes can have virtual functions, even though the virtual functions themselves can't be templates. It's fine if they have the same name; the argument types will be different.
Last edited on
You are basically asking: how do I add a new event without writing any code?
Well... yeah... ^^

Sorry, you have to write code.
damned ...
Is it at least possible that I don't have to change the AState class for each event that I add?

- You can stick with your current implementation (which is kind of weird, but whatever)
Nah, I have a problem with my current implementation. I don't like things that look weird to me.

- You can make a separate class to derive from for each new event (this is what I personally do, but with templates)
Could you show me an example of that please?

- You could go back to the stone ages and use an enum (like SFML)
no way.

Edit:
Okey, I found a better way to deal with the Events.
It was quite obvious but... yeah... don't know why I didn't just do it that way
1
2
3
4
5
struct IEvent {};
struct Button1Event : public IEvent {} event_button1;
struct Button2Event : public IEvent {} event_button2;
struct Timer1Event : public IEvent {} event_timer1;
struct Timer2Event : public IEvent {} event_timer2;

Does instanciating those variables actually benefit anything?
sizeof(IEvent) == 0 is true because it holds no data, right?
So i could just write Button1Event() everwhere and would have 0 memory loss?
Is there a reason to prefer one over the other?

Now the only problem that remains is that I have to modify the AState Class whenever I want to have a new Event...
I went over a few approaches but none of them worked:
- make an EventHandler in each class and then call those virtual functions over that one
- try casting the EventHandler to all Event types (i think that's where the enum came from)
- I tried the Visitor pattern, which was a complete failure
Last edited on
It doesn't make sense to instantiate the classes because it doesn't make sense for the classes to be empty.

The smallest possible addressable unit in C++ is one byte. Additionally, different instances are required to have different memory addresses. Therefore, an empty class has a sizeof 1 byte.

With my implementation, event types know who is listening to them (static data structure), and it is the responsibility of an event instance to notify all its listeners. All you need to do to fire an event is e->fire(); and let polymorphism handle the rest.
It doesn't make sense to instantiate the classes because it doesn't make sense for the classes to be empty.
They get a function to check if the Event occured or not.
Since there is no "static virtual" function I have to make an instance of the struct/class, right?

With my implementation, event types know who is listening to them (static data structure), and it is the responsibility of an event instance to notify all its listeners. All you need to do to fire an event is e->fire(); and let polymorphism handle the rest.
The only state that should know that an event occured is the current state.
Last edited on
If you only have one listener, period, I don't know why you're trying to use an event system. That's like using public key encryption to communicate with the only other human in existence.
Yeah well, I only have one listener but that listener may be any of the humans around me.

Well, I got some results and I'm implementing the states and events as singletons.

I'll post a new question, thanks for trying to help me.
Events do not make sense as singletons because each event carries its own information about that particular event. Imagine multiple PostSubmitted events - each one has a different author and content.

In general, you should try to avoid singletons as much as possible - their uses are far and few between.
Last edited on
Topic archived. No new replies allowed.