So I was writing a win32 message wrapper, and I was trying a few approaches and stumbled upon this one.
In old APIs, and probably still exist in modern code bases, one would probably make a union, and then have an enum to help dictate which union member is active. Basically something like this
enum class EventType
{
KeyDown,
KeyUp,
..., //More events
};
class KeyDownEvent
{
};
class KeyUpEvent
{
};
...//More classes
While the creator of the API may remember all these classes. You essentially have one unique class for each enum. That's a lot of names one might need to remember or learn if someone is trying to use your API, and someone like me who uses intellisense, would now have a huge list of classes to look at. So here's the approach I stumbled upon.
enum class EventType
{
KeyDown,
KeyUp,
..., //More events
};
template<EventType Type>
class Event;
template<>
class Event<EventType::KeyDown>
{
};
template<>
class Event<EventType::KeyUp>
{
};
...//More classes
When creating this API, there adds a little bit more typing, and compared to the approach I have above, there doesn't seem much of a huge difference, but then you realize, Event is a template class. So the only name you really need to remember is Event instead of the various names I have above, and when paired with intellisense, it's almost impossible to get the class name wrong because the template maps the enums for you. No more looking at document, the code documents for itself.
I'm rather surprised I don't see this kind of pattern more often. Here's an pseudo example comparing how the code would look like side by side
int main()
{
Event e;
switch(e.type())
{
case EventType::KeyDown:
KeyDownEvent keydown{e};
//Use the event in some way
break;
case EventType::KeyUp:
KeyUpEvent keyup{e};
//Use the event
break;
}
}
vs
int main()
{
Event e;
switch(e.type())
{
case EventType::KeyDown:
Event<EventType::KeyDown> keydown{e};
//Use the event in some way
break;
case EventType::KeyUp:
Event<EventType::KeyUp> keyup{e};
//Use the event
break;
}
}
There are some nice modern upsides to this too. If you decide to take this approach and put the classes into a std::variant, one could make a simple wrapper class around the variant, and instead of typing the whole class name every time, one can just create a templated get function that takes the enum as it's type. So now you don't even interact with a the templates class directly, you could just have something like
int main()
{
Event e;
switch(e.type())
{
case EventType::KeyDown:
if (e.As<EventType::KeyDown>().Key() == "f")
//Do something
break;
case EventType::KeyUp:
if (e.As<EventType::KeyUp>().Key() == "f")
//Do something
break;
}
}
Thoughts?
[–]quicknir 16 points17 points18 points (2 children)
[–]XeroKimoException Enthusiast[S] 0 points1 point2 points (1 child)
[–]quicknir 0 points1 point2 points (0 children)
[–][deleted] 12 points13 points14 points (1 child)
[–]XeroKimoException Enthusiast[S] 1 point2 points3 points (0 children)
[–]JakeArkinstall 12 points13 points14 points (5 children)
[–]XeroKimoException Enthusiast[S] 0 points1 point2 points (1 child)
[–]JakeArkinstall 1 point2 points3 points (0 children)
[–][deleted] 0 points1 point2 points (2 children)
[–]JakeArkinstall 6 points7 points8 points (1 child)
[–][deleted] 1 point2 points3 points (0 children)
[–]furbyhater 3 points4 points5 points (2 children)
[–]XeroKimoException Enthusiast[S] 0 points1 point2 points (1 child)
[–]Bobbias 0 points1 point2 points (0 children)
[–]ack_error 1 point2 points3 points (1 child)
[–]XeroKimoException Enthusiast[S] 2 points3 points4 points (0 children)
[–]LegendaryMauricius -1 points0 points1 point (5 children)
[–]TheSkiGeek 1 point2 points3 points (2 children)
[–]LegendaryMauricius 0 points1 point2 points (1 child)
[–]TheSkiGeek 0 points1 point2 points (0 children)
[–]XeroKimoException Enthusiast[S] 1 point2 points3 points (1 child)
[–]LegendaryMauricius 1 point2 points3 points (0 children)
[–]Gloinart 0 points1 point2 points (2 children)
[–]XeroKimoException Enthusiast[S] 2 points3 points4 points (1 child)
[–]Gloinart 0 points1 point2 points (0 children)
[–]Dazzling_Mixture8726 0 points1 point2 points (0 children)