If you want to skip reading and get to the code, then see some kind of C++ static polymorphism in the GitHub repository.
I’m a fan of tasks. I enjoy each time I implement any kind of system that executes tasks, from very simple ones (based on a list of tasks executed on a single thread) to multithreaded ones with features like cancellation and dynamic concurrency level.
My first encounter with the idea of having a list of objects that I iterate and call a function for each one of them was when I had to implement a feature that dynamically restricted users’ access to some content based on various conditions. You can think about a lot of if statements. I don’t like if statements, I struggle to avoid them because each one of them brings new responsibility, test cases, and maintenance costs. And I really enjoy seeing product and management people happy when their requirements are implemented at reasonable times. And being productive is a lot about code.
A way to decouple code is, of course, to separate concerns. And if you’re in a case with multiple concerns serving the same concept, you could use a polymorphic approach. You can have an interface for a task, some tasks implementations, and something to run all the tasks when needed. Everything you’ll see in this article is a light version because I’m focusing on the idea, not on details.
#include <array>
#include <iostream>
#include <memory>
class Task {
public:
virtual void Execute() = 0;
};
template <typename T>
struct Executor {
T& tasks;
void Execute()
{
for (auto& task : tasks) {
task->Execute();
}
}
};
class A : public Task {
public:
void Execute() override { std::cout << 1; }
};
class B : public Task {
public:
void Execute() override { std::cout << 2; }
};
int main()
{
using Tasks = std::array<std::unique_ptr<Task>, 2>;
Tasks tasks{
std::make_unique<A>(),
std::make_unique<B>(),
};
Executor<Tasks> executor{tasks};
executor.Execute();
}
Now I’ll add some constraints for learning purposes. Sometimes performance matters and you can’t always use the latest C++ standards, so I’ll go with these:
-
- C++ 11
- No heap allocations
- Minimum stack allocations
- No virtual methods
And I’m entering the world of templates because this can help me achieve compile-time polymorphism (C++ static polymorphism), and that’s what I’m aiming for. Continue reading Executing tasks based on static polymorphism