-
Notifications
You must be signed in to change notification settings - Fork 4
template abuse
in this project, i heavily (ab)used templates for my cpu implementation.
template params are compile time, meaning that at run time, you cannot do this:
int bpp = get_bpp();
handler<data>(); // <- not valid!
however, you can still do stuff at runtime quite easily like so:
int bpp = get_bpp();
if (bpp == 8)
{
handler<8>();
}
else if (bpp == 4)
{
handler<4>();
}
you might think there's no point in this, just have the handler check
the bpp. well yes, you can do that, the point of the template here is to remove the (assumed) expensive if()
withing handler()
.
the above is all well and good when the function takes one param, but what if it takes multiple params? let's look at an example of it taking 2:
int bpp = get_bpp();
bool blend = is_blend_enabled();
if (bpp == 8)
{
if (blend)
{
handler<8, true>();
}
else
{
handler<8, false>();
}
}
else if (bpp == 4)
{
if (blend)
{
handler<4, true>();
}
else
{
handler<4, false>();
}
}
well that got messy really quickly! someone call the DRY police! this is just 2 params, what if you have a function that takes 4,5 or 6 params...i'm not even going to write an example of this.
there's a way to make this a lot cleaner to write and read.
here's an example with 4 params:
template<int bpp, bool blend, bool window, bool window_blend>
void render() { ... } // <-- actual render function
template<int bpp, bool blend, bool window>
void render(bool window_blend)
{
if (window_blend) {
render<bpp, blend, window, true>();
} else {
render<bpp, blend, window, false>();
}
}
template<int bpp, bool blend>
void render(bool window, bool window_blend)
{
if (window) {
render<bpp, blend, true>(window_blend);
} else {
render<bpp, blend, false>(window_blend);
}
}
template<int bpp>
void render(bool blend, bool window, bool window_blend)
{
if (blend) {
render<bpp, true>(window, window_blend);
} else {
render<bpp, false>(window, window_blend);
}
}
// start here
void render(int bpp, bool blend, bool window, bool window_blend)
{
if (bpp == 8) {
render<8>(blend, window, window_blend);
} else {
render<4>(blend, window, window_blend);
}
}
it's still not great, but this is the best that i came up with (for now).
this doesn't mean you should replace all branchs within a loop with this template mess above. the purpose of the above is when there are if()
that can be move out of the tight loop of a function, but the rest of the code mostly stays the same.
instead of copying the same function multiple times, only removing a couple of if()
in each version, i instead have the template stamp out all the functions for me.
the render function would now look like this:
template<int bpp, bool blend, bool window, bool window_blend>
void render()
{
for (int i = 0; i < 160; i++) {
if constexpr (bpp == 8) {
// do stuff
} else {
// do stuff
}
if constexpr (blend) {
// do stuff
} else {
// do stuff
}
if constexpr (window) {
// do stuff
} else {
// do stuff
}
if constexpr (window_blend) {
// do stuff
} else {
// do stuff
}
}
}
obviously, none of the above is real code that i am using, it's just to give an example of how it can be used.
i did sort of use this is code before, but have since scrapped it, due to my render code being broken. i do plan to sort of use it again once my render code actually works.
feel free to open an issue / PR if you have any suggestions to improve this doc.